Skip to content

Commit 9de7474

Browse files
committed
Auto merge of #99512 - nikic:llvm-15-fixes, r=cuviper
LLVM 15 compatibility fixes These are LLVM 15 compatibility fixes split out from #99464. There are three changes here: * Emit elementtype attribtue for ldrex/strex intrinsics. This is requires as part of the opaque pointers migration. * Make more tests compatible with opaque pointers. These are either new or aren't run on x86. * Remove a test for `#[rustc_allocator]`. Since #99574 there are more requirement on the function signature. I dropped the test entirely, since we already test the effect of the attribute elsewhere. * The main change: When a worker thread emits an error, wait for other threads to finish before unwinding the main thread and exiting. Otherwise workers may end up using globals for which destructors have already been run. This was probably never quite correct, but became an active problem with LLVM 15, because it started using global dtors in critical places, as part of ManagedStatic removal. Fixes #99432 (and probably also #95679). r? `@cuviper`
2 parents c8893cc + 1433b29 commit 9de7474

File tree

9 files changed

+103
-103
lines changed

9 files changed

+103
-103
lines changed

compiler/rustc_codegen_llvm/src/abi.rs

+16
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,22 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
569569
&[cmse_nonsecure_call],
570570
);
571571
}
572+
573+
// Some intrinsics require that an elementtype attribute (with the pointee type of a
574+
// pointer argument) is added to the callsite.
575+
let element_type_index = unsafe { llvm::LLVMRustGetElementTypeArgIndex(callsite) };
576+
if element_type_index >= 0 {
577+
let arg_ty = self.args[element_type_index as usize].layout.ty;
578+
let pointee_ty = arg_ty.builtin_deref(true).expect("Must be pointer argument").ty;
579+
let element_type_attr = unsafe {
580+
llvm::LLVMRustCreateElementTypeAttr(bx.llcx, bx.layout_of(pointee_ty).llvm_type(bx))
581+
};
582+
attributes::apply_to_callsite(
583+
callsite,
584+
llvm::AttributePlace::Argument(element_type_index as u32),
585+
&[element_type_attr],
586+
);
587+
}
572588
}
573589
}
574590

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1192,6 +1192,7 @@ extern "C" {
11921192
pub fn LLVMRustCreateDereferenceableOrNullAttr(C: &Context, bytes: u64) -> &Attribute;
11931193
pub fn LLVMRustCreateByValAttr<'a>(C: &'a Context, ty: &'a Type) -> &'a Attribute;
11941194
pub fn LLVMRustCreateStructRetAttr<'a>(C: &'a Context, ty: &'a Type) -> &'a Attribute;
1195+
pub fn LLVMRustCreateElementTypeAttr<'a>(C: &'a Context, ty: &'a Type) -> &'a Attribute;
11951196
pub fn LLVMRustCreateUWTableAttr(C: &Context, async_: bool) -> &Attribute;
11961197
pub fn LLVMRustCreateAllocSizeAttr(C: &Context, size_arg: u32) -> &Attribute;
11971198
pub fn LLVMRustCreateAllocKindAttr(C: &Context, size_arg: u64) -> &Attribute;
@@ -2541,4 +2542,6 @@ extern "C" {
25412542

25422543
#[allow(improper_ctypes)]
25432544
pub fn LLVMRustGetMangledName(V: &Value, out: &RustString);
2545+
2546+
pub fn LLVMRustGetElementTypeArgIndex(CallSite: &Value) -> i32;
25442547
}

compiler/rustc_codegen_ssa/src/back/write.rs

+44-27
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ use rustc_target::spec::{MergeFunctions, SanitizerSet};
3737
use std::any::Any;
3838
use std::fs;
3939
use std::io;
40+
use std::marker::PhantomData;
4041
use std::mem;
4142
use std::path::{Path, PathBuf};
4243
use std::str;
@@ -475,10 +476,13 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
475476
metadata_module,
476477
crate_info,
477478

478-
coordinator_send,
479479
codegen_worker_receive,
480480
shared_emitter_main,
481-
future: coordinator_thread,
481+
coordinator: Coordinator {
482+
sender: coordinator_send,
483+
future: Some(coordinator_thread),
484+
phantom: PhantomData,
485+
},
482486
output_filenames: tcx.output_filenames(()).clone(),
483487
}
484488
}
@@ -1273,6 +1277,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
12731277
// work to be done.
12741278
while !codegen_done
12751279
|| running > 0
1280+
|| main_thread_worker_state == MainThreadWorkerState::LLVMing
12761281
|| (!codegen_aborted
12771282
&& !(work_items.is_empty()
12781283
&& needs_fat_lto.is_empty()
@@ -1470,14 +1475,12 @@ fn start_executing_work<B: ExtraBackendMethods>(
14701475
if !cgcx.opts.unstable_opts.no_parallel_llvm {
14711476
helper.request_token();
14721477
}
1473-
assert!(!codegen_aborted);
14741478
assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning);
14751479
main_thread_worker_state = MainThreadWorkerState::Idle;
14761480
}
14771481

14781482
Message::CodegenComplete => {
14791483
codegen_done = true;
1480-
assert!(!codegen_aborted);
14811484
assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning);
14821485
main_thread_worker_state = MainThreadWorkerState::Idle;
14831486
}
@@ -1489,10 +1492,8 @@ fn start_executing_work<B: ExtraBackendMethods>(
14891492
// then conditions above will ensure no more work is spawned but
14901493
// we'll keep executing this loop until `running` hits 0.
14911494
Message::CodegenAborted => {
1492-
assert!(!codegen_aborted);
14931495
codegen_done = true;
14941496
codegen_aborted = true;
1495-
assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning);
14961497
}
14971498
Message::Done { result: Ok(compiled_module), worker_id } => {
14981499
free_worker(worker_id);
@@ -1532,13 +1533,20 @@ fn start_executing_work<B: ExtraBackendMethods>(
15321533
Message::Done { result: Err(None), worker_id: _ } => {
15331534
bug!("worker thread panicked");
15341535
}
1535-
Message::Done { result: Err(Some(WorkerFatalError)), worker_id: _ } => {
1536-
return Err(());
1536+
Message::Done { result: Err(Some(WorkerFatalError)), worker_id } => {
1537+
// Similar to CodegenAborted, wait for remaining work to finish.
1538+
free_worker(worker_id);
1539+
codegen_done = true;
1540+
codegen_aborted = true;
15371541
}
15381542
Message::CodegenItem => bug!("the coordinator should not receive codegen requests"),
15391543
}
15401544
}
15411545

1546+
if codegen_aborted {
1547+
return Err(());
1548+
}
1549+
15421550
let needs_link = mem::take(&mut needs_link);
15431551
if !needs_link.is_empty() {
15441552
assert!(compiled_modules.is_empty());
@@ -1828,25 +1836,47 @@ impl SharedEmitterMain {
18281836
}
18291837
}
18301838

1839+
pub struct Coordinator<B: ExtraBackendMethods> {
1840+
pub sender: Sender<Box<dyn Any + Send>>,
1841+
future: Option<thread::JoinHandle<Result<CompiledModules, ()>>>,
1842+
// Only used for the Message type.
1843+
phantom: PhantomData<B>,
1844+
}
1845+
1846+
impl<B: ExtraBackendMethods> Coordinator<B> {
1847+
fn join(mut self) -> std::thread::Result<Result<CompiledModules, ()>> {
1848+
self.future.take().unwrap().join()
1849+
}
1850+
}
1851+
1852+
impl<B: ExtraBackendMethods> Drop for Coordinator<B> {
1853+
fn drop(&mut self) {
1854+
if let Some(future) = self.future.take() {
1855+
// If we haven't joined yet, signal to the coordinator that it should spawn no more
1856+
// work, and wait for worker threads to finish.
1857+
drop(self.sender.send(Box::new(Message::CodegenAborted::<B>)));
1858+
drop(future.join());
1859+
}
1860+
}
1861+
}
1862+
18311863
pub struct OngoingCodegen<B: ExtraBackendMethods> {
18321864
pub backend: B,
18331865
pub metadata: EncodedMetadata,
18341866
pub metadata_module: Option<CompiledModule>,
18351867
pub crate_info: CrateInfo,
1836-
pub coordinator_send: Sender<Box<dyn Any + Send>>,
18371868
pub codegen_worker_receive: Receiver<Message<B>>,
18381869
pub shared_emitter_main: SharedEmitterMain,
1839-
pub future: thread::JoinHandle<Result<CompiledModules, ()>>,
18401870
pub output_filenames: Arc<OutputFilenames>,
1871+
pub coordinator: Coordinator<B>,
18411872
}
18421873

18431874
impl<B: ExtraBackendMethods> OngoingCodegen<B> {
18441875
pub fn join(self, sess: &Session) -> (CodegenResults, FxHashMap<WorkProductId, WorkProduct>) {
18451876
let _timer = sess.timer("finish_ongoing_codegen");
18461877

18471878
self.shared_emitter_main.check(sess, true);
1848-
let future = self.future;
1849-
let compiled_modules = sess.time("join_worker_thread", || match future.join() {
1879+
let compiled_modules = sess.time("join_worker_thread", || match self.coordinator.join() {
18501880
Ok(Ok(compiled_modules)) => compiled_modules,
18511881
Ok(Err(())) => {
18521882
sess.abort_if_errors();
@@ -1894,26 +1924,13 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
18941924

18951925
// These are generally cheap and won't throw off scheduling.
18961926
let cost = 0;
1897-
submit_codegened_module_to_llvm(&self.backend, &self.coordinator_send, module, cost);
1927+
submit_codegened_module_to_llvm(&self.backend, &self.coordinator.sender, module, cost);
18981928
}
18991929

19001930
pub fn codegen_finished(&self, tcx: TyCtxt<'_>) {
19011931
self.wait_for_signal_to_codegen_item();
19021932
self.check_for_errors(tcx.sess);
1903-
drop(self.coordinator_send.send(Box::new(Message::CodegenComplete::<B>)));
1904-
}
1905-
1906-
/// Consumes this context indicating that codegen was entirely aborted, and
1907-
/// we need to exit as quickly as possible.
1908-
///
1909-
/// This method blocks the current thread until all worker threads have
1910-
/// finished, and all worker threads should have exited or be real close to
1911-
/// exiting at this point.
1912-
pub fn codegen_aborted(self) {
1913-
// Signal to the coordinator it should spawn no more work and start
1914-
// shutdown.
1915-
drop(self.coordinator_send.send(Box::new(Message::CodegenAborted::<B>)));
1916-
drop(self.future.join());
1933+
drop(self.coordinator.sender.send(Box::new(Message::CodegenComplete::<B>)));
19171934
}
19181935

19191936
pub fn check_for_errors(&self, sess: &Session) {

compiler/rustc_codegen_ssa/src/base.rs

+4-54
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ use rustc_target::abi::{Align, VariantIdx};
3939

4040
use std::collections::BTreeSet;
4141
use std::convert::TryFrom;
42-
use std::ops::{Deref, DerefMut};
4342
use std::time::{Duration, Instant};
4443

4544
use itertools::Itertools;
@@ -583,7 +582,6 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
583582
metadata_module,
584583
codegen_units.len(),
585584
);
586-
let ongoing_codegen = AbortCodegenOnDrop::<B>(Some(ongoing_codegen));
587585

588586
// Codegen an allocator shim, if necessary.
589587
//
@@ -704,7 +702,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
704702

705703
submit_codegened_module_to_llvm(
706704
&backend,
707-
&ongoing_codegen.coordinator_send,
705+
&ongoing_codegen.coordinator.sender,
708706
module,
709707
cost,
710708
);
@@ -714,7 +712,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
714712
submit_pre_lto_module_to_llvm(
715713
&backend,
716714
tcx,
717-
&ongoing_codegen.coordinator_send,
715+
&ongoing_codegen.coordinator.sender,
718716
CachedModuleCodegen {
719717
name: cgu.name().to_string(),
720718
source: cgu.previous_work_product(tcx),
@@ -725,7 +723,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
725723
CguReuse::PostLto => {
726724
submit_post_lto_module_to_llvm(
727725
&backend,
728-
&ongoing_codegen.coordinator_send,
726+
&ongoing_codegen.coordinator.sender,
729727
CachedModuleCodegen {
730728
name: cgu.name().to_string(),
731729
source: cgu.previous_work_product(tcx),
@@ -752,55 +750,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
752750
}
753751

754752
ongoing_codegen.check_for_errors(tcx.sess);
755-
756-
ongoing_codegen.into_inner()
757-
}
758-
759-
/// A curious wrapper structure whose only purpose is to call `codegen_aborted`
760-
/// when it's dropped abnormally.
761-
///
762-
/// In the process of working on rust-lang/rust#55238 a mysterious segfault was
763-
/// stumbled upon. The segfault was never reproduced locally, but it was
764-
/// suspected to be related to the fact that codegen worker threads were
765-
/// sticking around by the time the main thread was exiting, causing issues.
766-
///
767-
/// This structure is an attempt to fix that issue where the `codegen_aborted`
768-
/// message will block until all workers have finished. This should ensure that
769-
/// even if the main codegen thread panics we'll wait for pending work to
770-
/// complete before returning from the main thread, hopefully avoiding
771-
/// segfaults.
772-
///
773-
/// If you see this comment in the code, then it means that this workaround
774-
/// worked! We may yet one day track down the mysterious cause of that
775-
/// segfault...
776-
struct AbortCodegenOnDrop<B: ExtraBackendMethods>(Option<OngoingCodegen<B>>);
777-
778-
impl<B: ExtraBackendMethods> AbortCodegenOnDrop<B> {
779-
fn into_inner(mut self) -> OngoingCodegen<B> {
780-
self.0.take().unwrap()
781-
}
782-
}
783-
784-
impl<B: ExtraBackendMethods> Deref for AbortCodegenOnDrop<B> {
785-
type Target = OngoingCodegen<B>;
786-
787-
fn deref(&self) -> &OngoingCodegen<B> {
788-
self.0.as_ref().unwrap()
789-
}
790-
}
791-
792-
impl<B: ExtraBackendMethods> DerefMut for AbortCodegenOnDrop<B> {
793-
fn deref_mut(&mut self) -> &mut OngoingCodegen<B> {
794-
self.0.as_mut().unwrap()
795-
}
796-
}
797-
798-
impl<B: ExtraBackendMethods> Drop for AbortCodegenOnDrop<B> {
799-
fn drop(&mut self) {
800-
if let Some(codegen) = self.0.take() {
801-
codegen.codegen_aborted();
802-
}
803-
}
753+
ongoing_codegen
804754
}
805755

806756
impl CrateInfo {

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "llvm/IR/GlobalVariable.h"
77
#include "llvm/IR/Instructions.h"
88
#include "llvm/IR/Intrinsics.h"
9+
#include "llvm/IR/IntrinsicsARM.h"
910
#include "llvm/IR/Mangler.h"
1011
#include "llvm/Object/Archive.h"
1112
#include "llvm/Object/COFFImportFile.h"
@@ -300,6 +301,14 @@ extern "C" LLVMAttributeRef LLVMRustCreateStructRetAttr(LLVMContextRef C, LLVMTy
300301
return wrap(Attribute::getWithStructRetType(*unwrap(C), unwrap(Ty)));
301302
}
302303

304+
extern "C" LLVMAttributeRef LLVMRustCreateElementTypeAttr(LLVMContextRef C, LLVMTypeRef Ty) {
305+
#if LLVM_VERSION_GE(15, 0)
306+
return wrap(Attribute::get(*unwrap(C), Attribute::ElementType, unwrap(Ty)));
307+
#else
308+
report_fatal_error("Should not be needed on LLVM < 15");
309+
#endif
310+
}
311+
303312
extern "C" LLVMAttributeRef LLVMRustCreateUWTableAttr(LLVMContextRef C, bool Async) {
304313
#if LLVM_VERSION_LT(15, 0)
305314
return wrap(Attribute::get(*unwrap(C), Attribute::UWTable));
@@ -1943,3 +1952,16 @@ extern "C" LLVMValueRef LLVMGetAggregateElement(LLVMValueRef C, unsigned Idx) {
19431952
return wrap(unwrap<Constant>(C)->getAggregateElement(Idx));
19441953
}
19451954
#endif
1955+
1956+
extern "C" int32_t LLVMRustGetElementTypeArgIndex(LLVMValueRef CallSite) {
1957+
#if LLVM_VERSION_GE(15, 0)
1958+
auto *CB = unwrap<CallBase>(CallSite);
1959+
switch (CB->getIntrinsicID()) {
1960+
case Intrinsic::arm_ldrex:
1961+
return 0;
1962+
case Intrinsic::arm_strex:
1963+
return 1;
1964+
}
1965+
#endif
1966+
return -1;
1967+
}

src/test/codegen/function-arguments.rs

-7
Original file line numberDiff line numberDiff line change
@@ -233,10 +233,3 @@ pub fn enum_id_1(x: Option<Result<u16, u16>>) -> Option<Result<u16, u16>> {
233233
pub fn enum_id_2(x: Option<u8>) -> Option<u8> {
234234
x
235235
}
236-
237-
// CHECK: noalias {{i8\*|ptr}} @allocator()
238-
#[no_mangle]
239-
#[rustc_allocator]
240-
pub fn allocator() -> *const i8 {
241-
std::ptr::null()
242-
}

src/test/codegen/repr-transparent-aggregates-2.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,19 @@ pub enum TeBigS {
3737
Variant(BigS),
3838
}
3939

40-
// CHECK: define void @test_BigS(%BigS* [[BIGS_RET_ATTRS1:.*]] sret(%BigS) [[BIGS_RET_ATTRS2:.*]], [16 x i32]
40+
// CHECK: define void @test_BigS({{%BigS\*|ptr}} [[BIGS_RET_ATTRS1:.*]] sret(%BigS) [[BIGS_RET_ATTRS2:.*]], [16 x i32]
4141
#[no_mangle]
4242
pub extern fn test_BigS(_: BigS) -> BigS { loop {} }
4343

44-
// CHECK: define void @test_TsBigS(%TsBigS* [[BIGS_RET_ATTRS1]] sret(%TsBigS) [[BIGS_RET_ATTRS2]], [16 x i32]
44+
// CHECK: define void @test_TsBigS({{%TsBigS\*|ptr}} [[BIGS_RET_ATTRS1]] sret(%TsBigS) [[BIGS_RET_ATTRS2]], [16 x i32]
4545
#[no_mangle]
4646
pub extern fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} }
4747

48-
// CHECK: define void @test_TuBigS(%TuBigS* [[BIGS_RET_ATTRS1]] sret(%TuBigS) [[BIGS_RET_ATTRS2]], [16 x i32]
48+
// CHECK: define void @test_TuBigS({{%TuBigS\*|ptr}} [[BIGS_RET_ATTRS1]] sret(%TuBigS) [[BIGS_RET_ATTRS2]], [16 x i32]
4949
#[no_mangle]
5050
pub extern fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} }
5151

52-
// CHECK: define void @test_TeBigS(%"TeBigS::Variant"* [[BIGS_RET_ATTRS1]] sret(%"TeBigS::Variant") [[BIGS_RET_ATTRS2]], [16 x i32]
52+
// CHECK: define void @test_TeBigS({{%"TeBigS::Variant"\*|ptr}} [[BIGS_RET_ATTRS1]] sret(%"TeBigS::Variant") [[BIGS_RET_ATTRS2]], [16 x i32]
5353
#[no_mangle]
5454
pub extern fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} }
5555

@@ -73,18 +73,18 @@ pub enum TeBigU {
7373
Variant(BigU),
7474
}
7575

76-
// CHECK: define void @test_BigU(%BigU* [[BIGU_RET_ATTRS1:.*]] sret(%BigU) [[BIGU_RET_ATTRS2:.*]], [16 x i32]
76+
// CHECK: define void @test_BigU({{%BigU\*|ptr}} [[BIGU_RET_ATTRS1:.*]] sret(%BigU) [[BIGU_RET_ATTRS2:.*]], [16 x i32]
7777
#[no_mangle]
7878
pub extern fn test_BigU(_: BigU) -> BigU { loop {} }
7979

80-
// CHECK: define void @test_TsBigU(%TsBigU* [[BIGU_RET_ATTRS1]] sret(%TsBigU) [[BIGU_RET_ATTRS2]], [16 x i32]
80+
// CHECK: define void @test_TsBigU({{%TsBigU\*|ptr}} [[BIGU_RET_ATTRS1]] sret(%TsBigU) [[BIGU_RET_ATTRS2]], [16 x i32]
8181
#[no_mangle]
8282
pub extern fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} }
8383

84-
// CHECK: define void @test_TuBigU(%TuBigU* [[BIGU_RET_ATTRS1]] sret(%TuBigU) [[BIGU_RET_ATTRS2]], [16 x i32]
84+
// CHECK: define void @test_TuBigU({{%TuBigU\*|ptr}} [[BIGU_RET_ATTRS1]] sret(%TuBigU) [[BIGU_RET_ATTRS2]], [16 x i32]
8585
#[no_mangle]
8686
pub extern fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} }
8787

88-
// CHECK: define void @test_TeBigU(%"TeBigU::Variant"* [[BIGU_RET_ATTRS1]] sret(%"TeBigU::Variant") [[BIGU_RET_ATTRS2]], [16 x i32]
88+
// CHECK: define void @test_TeBigU({{%"TeBigU::Variant"\*|ptr}} [[BIGU_RET_ATTRS1]] sret(%"TeBigU::Variant") [[BIGU_RET_ATTRS2]], [16 x i32]
8989
#[no_mangle]
9090
pub extern fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} }

0 commit comments

Comments
 (0)