Skip to content

Commit fd0384b

Browse files
committed
Auto merge of #155793 - JonathanBrouwer:rollup-q75rqML, r=JonathanBrouwer
Rollup of 4 pull requests Successful merges: - #146181 (Add intrinsic for launch-sized workgroup memory on GPUs) - #155065 (Error on invalid macho section specifier) - #155676 ( Reject implementing const Drop for types that are not const `Destruct` already) - #155783 (Do not suggest internal cfg trace attributes)
2 parents 9838411 + 0258ca6 commit fd0384b

51 files changed

Lines changed: 704 additions & 165 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

compiler/rustc_abi/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1753,6 +1753,9 @@ pub struct AddressSpace(pub u32);
17531753
impl AddressSpace {
17541754
/// LLVM's `0` address space.
17551755
pub const ZERO: Self = AddressSpace(0);
1756+
/// The address space for workgroup memory on nvptx and amdgpu.
1757+
/// See e.g. the `gpu_launch_sized_workgroup_mem` intrinsic for details.
1758+
pub const GPU_WORKGROUP: Self = AddressSpace(3);
17561759
}
17571760

17581761
/// How many scalable vectors are in a `BackendRepr::ScalableVector`?

compiler/rustc_attr_parsing/src/attributes/link_attrs.rs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ use crate::attributes::cfg::parse_cfg_entry;
1616
use crate::session_diagnostics::{
1717
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic,
1818
ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink, InvalidLinkModifier,
19-
LinkFrameworkApple, LinkOrdinalOutOfRange, LinkRequiresName, MultipleModifiers,
20-
NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows, WholeArchiveNeedsStatic,
19+
InvalidMachoSection, InvalidMachoSectionReason, LinkFrameworkApple, LinkOrdinalOutOfRange,
20+
LinkRequiresName, MultipleModifiers, NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows,
21+
WholeArchiveNeedsStatic,
2122
};
2223

2324
pub(crate) struct LinkNameParser;
@@ -462,6 +463,29 @@ impl LinkParser {
462463

463464
pub(crate) struct LinkSectionParser;
464465

466+
fn check_link_section_macho(name: Symbol) -> Result<(), InvalidMachoSectionReason> {
467+
let mut parts = name.as_str().split(',').map(|s| s.trim());
468+
469+
// The segment can be empty.
470+
let _segment = parts.next();
471+
472+
// But the section is required.
473+
let section = match parts.next() {
474+
None | Some("") => return Err(InvalidMachoSectionReason::MissingSection),
475+
Some(section) => section,
476+
};
477+
478+
if section.len() > 16 {
479+
return Err(InvalidMachoSectionReason::SectionTooLong { section: section.to_string() });
480+
}
481+
482+
// LLVM also checks the other components of the section specifier, but that logic is hard to
483+
// keep in sync. We skip it here for now, assuming that if you got that far you'll be able
484+
// to interpret the LLVM errors.
485+
486+
Ok(())
487+
}
488+
465489
impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
466490
const PATH: &[Symbol] = &[sym::link_section];
467491
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
@@ -495,6 +519,18 @@ impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
495519
return None;
496520
}
497521

522+
// We (currently) only validate macho section specifiers.
523+
match cx.sess.target.binary_format {
524+
BinaryFormat::MachO => match check_link_section_macho(name) {
525+
Ok(()) => {}
526+
Err(reason) => {
527+
cx.emit_err(InvalidMachoSection { name_span: nv.value_span, reason });
528+
return None;
529+
}
530+
},
531+
BinaryFormat::Coff | BinaryFormat::Elf | BinaryFormat::Wasm | BinaryFormat::Xcoff => {}
532+
}
533+
498534
Some(LinkSection { name, span: cx.attr_span })
499535
}
500536
}

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,3 +1137,22 @@ pub(crate) struct UnstableAttrForAlreadyStableFeature {
11371137
#[label("the stability attribute annotates this item")]
11381138
pub item_span: Span,
11391139
}
1140+
1141+
#[derive(Diagnostic)]
1142+
#[diag("invalid Mach-O section specifier")]
1143+
pub(crate) struct InvalidMachoSection {
1144+
#[primary_span]
1145+
#[label("not a valid Mach-O section specifier")]
1146+
pub name_span: Span,
1147+
#[subdiagnostic]
1148+
pub reason: InvalidMachoSectionReason,
1149+
}
1150+
1151+
#[derive(Subdiagnostic)]
1152+
pub(crate) enum InvalidMachoSectionReason {
1153+
#[note("a Mach-O section specifier requires a segment and a section, separated by a comma")]
1154+
#[help("an example of a valid Mach-O section specifier is `__TEXT,__cstring`")]
1155+
MissingSection,
1156+
#[note("section name `{$section}` is longer than 16 bytes")]
1157+
SectionTooLong { section: String },
1158+
}

compiler/rustc_codegen_llvm/src/declare.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use std::borrow::Borrow;
1515

1616
use itertools::Itertools;
17+
use rustc_abi::AddressSpace;
1718
use rustc_codegen_ssa::traits::{MiscCodegenMethods, TypeMembershipCodegenMethods};
1819
use rustc_data_structures::fx::FxIndexSet;
1920
use rustc_middle::ty::{Instance, Ty};
@@ -104,6 +105,28 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
104105
)
105106
}
106107
}
108+
109+
/// Declare a global value in a specific address space.
110+
///
111+
/// If there’s a value with the same name already declared, the function will
112+
/// return its Value instead.
113+
pub(crate) fn declare_global_in_addrspace(
114+
&self,
115+
name: &str,
116+
ty: &'ll Type,
117+
addr_space: AddressSpace,
118+
) -> &'ll Value {
119+
debug!("declare_global(name={name:?}, addrspace={addr_space:?})");
120+
unsafe {
121+
llvm::LLVMRustGetOrInsertGlobalInAddrspace(
122+
(**self).borrow().llmod,
123+
name.as_c_char_ptr(),
124+
name.len(),
125+
ty,
126+
addr_space.0,
127+
)
128+
}
129+
}
107130
}
108131

109132
impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {

compiler/rustc_codegen_llvm/src/intrinsic.rs

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use std::ffi::c_uint;
33
use std::{assert_matches, iter, ptr};
44

55
use rustc_abi::{
6-
Align, BackendRepr, Float, HasDataLayout, Integer, NumScalableVectors, Primitive, Size,
7-
WrappingRange,
6+
AddressSpace, Align, BackendRepr, Float, HasDataLayout, Integer, NumScalableVectors, Primitive,
7+
Size, WrappingRange,
88
};
99
use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh, wants_wasm_eh};
1010
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
@@ -178,6 +178,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
178178
span: Span,
179179
) -> Result<(), ty::Instance<'tcx>> {
180180
let tcx = self.tcx;
181+
let llvm_version = crate::llvm_util::get_version();
181182

182183
let name = tcx.item_name(instance.def_id());
183184
let fn_args = instance.args;
@@ -194,7 +195,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
194195
| sym::maximum_number_nsz_f64
195196
| sym::maximum_number_nsz_f128
196197
// Need at least LLVM 22 for `min/maximumnum` to not crash LLVM.
197-
if crate::llvm_util::get_version() >= (22, 0, 0) =>
198+
if llvm_version >= (22, 0, 0) =>
198199
{
199200
let intrinsic_name = if name.as_str().starts_with("min") {
200201
"llvm.minimumnum"
@@ -420,7 +421,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
420421
}
421422

422423
// FIXME move into the branch below when LLVM 22 is the lowest version we support.
423-
sym::carryless_mul if crate::llvm_util::get_version() >= (22, 0, 0) => {
424+
sym::carryless_mul if llvm_version >= (22, 0, 0) => {
424425
let ty = args[0].layout.ty;
425426
if !ty.is_integral() {
426427
tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType {
@@ -620,6 +621,46 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
620621
return Ok(());
621622
}
622623

624+
sym::gpu_launch_sized_workgroup_mem => {
625+
// Generate an anonymous global per call, with these properties:
626+
// 1. The global is in the address space for workgroup memory
627+
// 2. It is an `external` global
628+
// 3. It is correctly aligned for the pointee `T`
629+
// All instances of extern addrspace(gpu_workgroup) globals are merged in the LLVM backend.
630+
// The name is irrelevant.
631+
// See https://docs.nvidia.com/cuda/cuda-c-programming-guide/#shared
632+
let name = if llvm_version < (23, 0, 0) && tcx.sess.target.arch == Arch::Nvptx64 {
633+
// The auto-assigned name for extern shared globals in the nvptx backend does
634+
// not compile in ptxas. Workaround this issue by assigning a name.
635+
// Fixed in LLVM 23.
636+
"gpu_launch_sized_workgroup_mem"
637+
} else {
638+
""
639+
};
640+
let global = self.declare_global_in_addrspace(
641+
name,
642+
self.type_array(self.type_i8(), 0),
643+
AddressSpace::GPU_WORKGROUP,
644+
);
645+
let ty::RawPtr(inner_ty, _) = result.layout.ty.kind() else { unreachable!() };
646+
// The alignment of the global is used to specify the *minimum* alignment that
647+
// must be obeyed by the GPU runtime.
648+
// When multiple of these global variables are used by a kernel, the maximum alignment is taken.
649+
// See https://github.com/llvm/llvm-project/blob/a271d07488a85ce677674bbe8101b10efff58c95/llvm/lib/Target/AMDGPU/AMDGPULowerModuleLDSPass.cpp#L821
650+
let alignment = self.align_of(*inner_ty).bytes() as u32;
651+
unsafe {
652+
// FIXME Workaround the above issue by taking maximum alignment if the global existed
653+
if tcx.sess.target.arch == Arch::Nvptx64 {
654+
if alignment > llvm::LLVMGetAlignment(global) {
655+
llvm::LLVMSetAlignment(global, alignment);
656+
}
657+
} else {
658+
llvm::LLVMSetAlignment(global, alignment);
659+
}
660+
}
661+
self.cx().const_pointercast(global, self.type_ptr())
662+
}
663+
623664
sym::amdgpu_dispatch_ptr => {
624665
let val = self.call_intrinsic("llvm.amdgcn.dispatch.ptr", &[], &[]);
625666
// Relying on `LLVMBuildPointerCast` to produce an addrspacecast

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,6 +2003,13 @@ unsafe extern "C" {
20032003
NameLen: size_t,
20042004
T: &'a Type,
20052005
) -> &'a Value;
2006+
pub(crate) fn LLVMRustGetOrInsertGlobalInAddrspace<'a>(
2007+
M: &'a Module,
2008+
Name: *const c_char,
2009+
NameLen: size_t,
2010+
T: &'a Type,
2011+
AddressSpace: c_uint,
2012+
) -> &'a Value;
20062013
pub(crate) fn LLVMRustGetNamedValue(
20072014
M: &Module,
20082015
Name: *const c_char,

compiler/rustc_codegen_ssa/src/mir/intrinsic.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
111111
sym::abort
112112
| sym::unreachable
113113
| sym::cold_path
114+
| sym::gpu_launch_sized_workgroup_mem
114115
| sym::breakpoint
115116
| sym::amdgpu_dispatch_ptr
116117
| sym::assert_zero_valid

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1098,8 +1098,8 @@ pub enum AttributeKind {
10981098

10991099
/// Represents [`#[link_section]`](https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute)
11001100
LinkSection {
1101-
name: Symbol,
11021101
span: Span,
1102+
name: Symbol,
11031103
},
11041104

11051105
/// Represents `#[linkage]`.

compiler/rustc_hir_analysis/src/check/always_applicable.rs

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
1111
use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
1212
use rustc_middle::span_bug;
1313
use rustc_middle::ty::util::CheckRegions;
14-
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypingMode};
14+
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode};
1515
use rustc_trait_selection::regions::InferCtxtRegionExt;
1616
use rustc_trait_selection::traits::{self, ObligationCtxt};
1717

@@ -65,6 +65,8 @@ pub(crate) fn check_drop_impl(
6565
adt_to_impl_args,
6666
)?;
6767

68+
ensure_all_fields_are_const_destruct(tcx, drop_impl_did, adt_def.did())?;
69+
6870
ensure_impl_predicates_are_implied_by_item_defn(
6971
tcx,
7072
drop_impl_did,
@@ -173,6 +175,64 @@ fn ensure_impl_params_and_item_params_correspond<'tcx>(
173175
Err(err.emit())
174176
}
175177

178+
fn ensure_all_fields_are_const_destruct<'tcx>(
179+
tcx: TyCtxt<'tcx>,
180+
impl_def_id: LocalDefId,
181+
adt_def_id: DefId,
182+
) -> Result<(), ErrorGuaranteed> {
183+
if !tcx.is_conditionally_const(impl_def_id) {
184+
return Ok(());
185+
}
186+
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
187+
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
188+
189+
let impl_span = tcx.def_span(impl_def_id.to_def_id());
190+
let env =
191+
ty::EarlyBinder::bind(tcx.param_env(impl_def_id)).instantiate_identity().skip_norm_wip();
192+
let args = ty::GenericArgs::identity_for_item(tcx, impl_def_id);
193+
let destruct_trait = tcx.lang_items().destruct_trait().unwrap();
194+
for field in tcx.adt_def(adt_def_id).all_fields() {
195+
let field_ty = field.ty(tcx, args);
196+
let cause = traits::ObligationCause::new(
197+
tcx.def_span(field.did),
198+
impl_def_id,
199+
ObligationCauseCode::Misc,
200+
);
201+
ocx.register_obligation(traits::Obligation::new(
202+
tcx,
203+
cause,
204+
env,
205+
ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
206+
trait_ref: ty::TraitRef::new(tcx, destruct_trait, [field_ty]),
207+
constness: ty::BoundConstness::Maybe,
208+
}),
209+
));
210+
}
211+
ocx.evaluate_obligations_error_on_ambiguity()
212+
.into_iter()
213+
.map(|error| {
214+
let ty::ClauseKind::HostEffect(eff) =
215+
error.root_obligation.predicate.expect_clause().kind().no_bound_vars().unwrap()
216+
else {
217+
unreachable!()
218+
};
219+
let field_ty = eff.trait_ref.self_ty();
220+
let diag = struct_span_code_err!(
221+
tcx.dcx(),
222+
error.root_obligation.cause.span,
223+
E0367,
224+
"`{field_ty}` does not implement `[const] Destruct`",
225+
)
226+
.with_span_note(impl_span, "required for this `Drop` impl");
227+
if field_ty.has_param() {
228+
// FIXME: suggest adding `[const] Destruct` by teaching
229+
// `suggest_restricting_param_bound` about const traits.
230+
}
231+
Err(diag.emit())
232+
})
233+
.collect()
234+
}
235+
176236
/// Confirms that all predicates defined on the `Drop` impl (`drop_impl_def_id`) are able to be
177237
/// proven from within `adt_def_id`'s environment. I.e. all the predicates on the impl are
178238
/// implied by the ADT being well formed.

compiler/rustc_hir_analysis/src/check/intrinsic.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
130130
| sym::forget
131131
| sym::frem_algebraic
132132
| sym::fsub_algebraic
133+
| sym::gpu_launch_sized_workgroup_mem
133134
| sym::is_val_statically_known
134135
| sym::log2f16
135136
| sym::log2f32
@@ -297,6 +298,7 @@ pub(crate) fn check_intrinsic_type(
297298
sym::field_offset => (1, 0, vec![], tcx.types.usize),
298299
sym::rustc_peek => (1, 0, vec![param(0)], param(0)),
299300
sym::caller_location => (0, 0, vec![], tcx.caller_location_ty()),
301+
sym::gpu_launch_sized_workgroup_mem => (1, 0, vec![], Ty::new_mut_ptr(tcx, param(0))),
300302
sym::assert_inhabited | sym::assert_zero_valid | sym::assert_mem_uninitialized_valid => {
301303
(1, 0, vec![], tcx.types.unit)
302304
}

0 commit comments

Comments
 (0)