Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 13c0180

Browse files
committedDec 5, 2024
Auto merge of rust-lang#133878 - fmease:rollup-ov1am8o, r=fmease
Rollup of 6 pull requests Successful merges: - rust-lang#127565 (Teach rustc about the Xtensa VaListImpl) - rust-lang#128004 (codegen `#[naked]` functions using global asm) - rust-lang#133256 (CI: use free runners for i686-gnu jobs) - rust-lang#133472 (Run TLS destructors for wasm32-wasip1-threads) - rust-lang#133632 (CI: split x86_64-msvc job) - rust-lang#133827 (CI: rfl: move job forward to Linux v6.13-rc1) r? `@ghost` `@rustbot` modify labels: rollup
2 parents acabb52 + a0f24c7 commit 13c0180

File tree

31 files changed

+892
-144
lines changed

31 files changed

+892
-144
lines changed
 

‎compiler/rustc_attr/src/builtin.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,21 @@ pub enum InlineAttr {
4949
Never,
5050
}
5151

52-
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, HashStable_Generic)]
52+
#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq, HashStable_Generic)]
5353
pub enum InstructionSetAttr {
5454
ArmA32,
5555
ArmT32,
5656
}
5757

58+
impl InstructionSetAttr {
59+
pub fn as_str(self) -> &'static str {
60+
match self {
61+
Self::ArmA32 => sym::a32.as_str(),
62+
Self::ArmT32 => sym::t32.as_str(),
63+
}
64+
}
65+
}
66+
5867
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
5968
pub enum OptimizeAttr {
6069
None,

‎compiler/rustc_codegen_gcc/src/asm.rs

+7
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,13 @@ impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
867867
template_str.push_str("\n.popsection");
868868
self.context.add_top_level_asm(None, &template_str);
869869
}
870+
871+
fn mangled_name(&self, instance: Instance<'tcx>) -> String {
872+
// TODO(@Amanieu): Additional mangling is needed on
873+
// some targets to add a leading underscore (Mach-O)
874+
// or byte count suffixes (x86 Windows).
875+
self.tcx.symbol_name(instance).name.to_string()
876+
}
870877
}
871878

872879
fn modifier_to_gcc(

‎compiler/rustc_codegen_llvm/src/asm.rs

+8
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,14 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
442442
);
443443
}
444444
}
445+
446+
fn mangled_name(&self, instance: Instance<'tcx>) -> String {
447+
let llval = self.get_fn(instance);
448+
llvm::build_string(|s| unsafe {
449+
llvm::LLVMRustGetMangledName(llval, s);
450+
})
451+
.expect("symbol is not valid UTF-8")
452+
}
445453
}
446454

447455
pub(crate) fn inline_asm_call<'ll>(

‎compiler/rustc_codegen_llvm/src/attributes.rs

+3-11
Original file line numberDiff line numberDiff line change
@@ -395,17 +395,9 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
395395
to_add.push(MemoryEffects::None.create_attr(cx.llcx));
396396
}
397397
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
398-
to_add.push(AttributeKind::Naked.create_attr(cx.llcx));
399-
// HACK(jubilee): "indirect branch tracking" works by attaching prologues to functions.
400-
// And it is a module-level attribute, so the alternative is pulling naked functions into
401-
// new LLVM modules. Otherwise LLVM's "naked" functions come with endbr prefixes per
402-
// https://github.com/rust-lang/rust/issues/98768
403-
to_add.push(AttributeKind::NoCfCheck.create_attr(cx.llcx));
404-
if llvm_util::get_version() < (19, 0, 0) {
405-
// Prior to LLVM 19, branch-target-enforcement was disabled by setting the attribute to
406-
// the string "false". Now it is disabled by absence of the attribute.
407-
to_add.push(llvm::CreateAttrStringValue(cx.llcx, "branch-target-enforcement", "false"));
408-
}
398+
// do nothing; a naked function is converted into an extern function
399+
// and a global assembly block. LLVM's support for naked functions is
400+
// not used.
409401
} else {
410402
// Do not set sanitizer attributes for naked functions.
411403
to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize));

‎compiler/rustc_codegen_llvm/src/va_arg.rs

+111-2
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,23 @@ use crate::type_::Type;
1010
use crate::type_of::LayoutLlvmExt;
1111
use crate::value::Value;
1212

13+
fn round_up_to_alignment<'ll>(
14+
bx: &mut Builder<'_, 'll, '_>,
15+
mut value: &'ll Value,
16+
align: Align,
17+
) -> &'ll Value {
18+
value = bx.add(value, bx.cx().const_i32(align.bytes() as i32 - 1));
19+
return bx.and(value, bx.cx().const_i32(-(align.bytes() as i32)));
20+
}
21+
1322
fn round_pointer_up_to_alignment<'ll>(
1423
bx: &mut Builder<'_, 'll, '_>,
1524
addr: &'ll Value,
1625
align: Align,
1726
ptr_ty: &'ll Type,
1827
) -> &'ll Value {
1928
let mut ptr_as_int = bx.ptrtoint(addr, bx.cx().type_isize());
20-
ptr_as_int = bx.add(ptr_as_int, bx.cx().const_i32(align.bytes() as i32 - 1));
21-
ptr_as_int = bx.and(ptr_as_int, bx.cx().const_i32(-(align.bytes() as i32)));
29+
ptr_as_int = round_up_to_alignment(bx, ptr_as_int, align);
2230
bx.inttoptr(ptr_as_int, ptr_ty)
2331
}
2432

@@ -270,6 +278,106 @@ fn emit_s390x_va_arg<'ll, 'tcx>(
270278
bx.load(val_type, val_addr, layout.align.abi)
271279
}
272280

281+
fn emit_xtensa_va_arg<'ll, 'tcx>(
282+
bx: &mut Builder<'_, 'll, 'tcx>,
283+
list: OperandRef<'tcx, &'ll Value>,
284+
target_ty: Ty<'tcx>,
285+
) -> &'ll Value {
286+
// Implementation of va_arg for Xtensa. There doesn't seem to be an authoritative source for
287+
// this, other than "what GCC does".
288+
//
289+
// The va_list type has three fields:
290+
// struct __va_list_tag {
291+
// int32_t *va_stk; // Arguments passed on the stack
292+
// int32_t *va_reg; // Arguments passed in registers, saved to memory by the prologue.
293+
// int32_t va_ndx; // Offset into the arguments, in bytes
294+
// };
295+
//
296+
// The first 24 bytes (equivalent to 6 registers) come from va_reg, the rest from va_stk.
297+
// Thus if va_ndx is less than 24, the next va_arg *may* read from va_reg,
298+
// otherwise it must come from va_stk.
299+
//
300+
// Primitive arguments are never split between registers and the stack. For example, if loading an 8 byte
301+
// primitive value and va_ndx = 20, we instead bump the offset and read everything from va_stk.
302+
let va_list_addr = list.immediate();
303+
// FIXME: handle multi-field structs that split across regsave/stack?
304+
let layout = bx.cx.layout_of(target_ty);
305+
let from_stack = bx.append_sibling_block("va_arg.from_stack");
306+
let from_regsave = bx.append_sibling_block("va_arg.from_regsave");
307+
let end = bx.append_sibling_block("va_arg.end");
308+
309+
// (*va).va_ndx
310+
let va_reg_offset = 4;
311+
let va_ndx_offset = va_reg_offset + 4;
312+
let offset_ptr =
313+
bx.inbounds_gep(bx.type_i8(), va_list_addr, &[bx.cx.const_usize(va_ndx_offset)]);
314+
315+
let offset = bx.load(bx.type_i32(), offset_ptr, bx.tcx().data_layout.i32_align.abi);
316+
let offset = round_up_to_alignment(bx, offset, layout.align.abi);
317+
318+
let slot_size = layout.size.align_to(Align::from_bytes(4).unwrap()).bytes() as i32;
319+
320+
// Update the offset in va_list, by adding the slot's size.
321+
let offset_next = bx.add(offset, bx.const_i32(slot_size));
322+
323+
// Figure out where to look for our value. We do that by checking the end of our slot (offset_next).
324+
// If that is within the regsave area, then load from there. Otherwise load from the stack area.
325+
let regsave_size = bx.const_i32(24);
326+
let use_regsave = bx.icmp(IntPredicate::IntULE, offset_next, regsave_size);
327+
bx.cond_br(use_regsave, from_regsave, from_stack);
328+
329+
bx.switch_to_block(from_regsave);
330+
// update va_ndx
331+
bx.store(offset_next, offset_ptr, bx.tcx().data_layout.pointer_align.abi);
332+
333+
// (*va).va_reg
334+
let regsave_area_ptr =
335+
bx.inbounds_gep(bx.type_i8(), va_list_addr, &[bx.cx.const_usize(va_reg_offset)]);
336+
let regsave_area =
337+
bx.load(bx.type_ptr(), regsave_area_ptr, bx.tcx().data_layout.pointer_align.abi);
338+
let regsave_value_ptr = bx.inbounds_gep(bx.type_i8(), regsave_area, &[offset]);
339+
bx.br(end);
340+
341+
bx.switch_to_block(from_stack);
342+
343+
// The first time we switch from regsave to stack we needs to adjust our offsets a bit.
344+
// va_stk is set up such that the first stack argument is always at va_stk + 32.
345+
// The corrected offset is written back into the va_list struct.
346+
347+
// let offset_corrected = cmp::max(offset, 32);
348+
let stack_offset_start = bx.const_i32(32);
349+
let needs_correction = bx.icmp(IntPredicate::IntULE, offset, stack_offset_start);
350+
let offset_corrected = bx.select(needs_correction, stack_offset_start, offset);
351+
352+
// let offset_next_corrected = offset_corrected + slot_size;
353+
// va_ndx = offset_next_corrected;
354+
let offset_next_corrected = bx.add(offset_next, bx.const_i32(slot_size));
355+
// update va_ndx
356+
bx.store(offset_next_corrected, offset_ptr, bx.tcx().data_layout.pointer_align.abi);
357+
358+
// let stack_value_ptr = unsafe { (*va).va_stk.byte_add(offset_corrected) };
359+
let stack_area_ptr = bx.inbounds_gep(bx.type_i8(), va_list_addr, &[bx.cx.const_usize(0)]);
360+
let stack_area = bx.load(bx.type_ptr(), stack_area_ptr, bx.tcx().data_layout.pointer_align.abi);
361+
let stack_value_ptr = bx.inbounds_gep(bx.type_i8(), stack_area, &[offset_corrected]);
362+
bx.br(end);
363+
364+
bx.switch_to_block(end);
365+
366+
// On big-endian, for values smaller than the slot size we'd have to align the read to the end
367+
// of the slot rather than the start. While the ISA and GCC support big-endian, all the Xtensa
368+
// targets supported by rustc are litte-endian so don't worry about it.
369+
370+
// if from_regsave {
371+
// unsafe { *regsave_value_ptr }
372+
// } else {
373+
// unsafe { *stack_value_ptr }
374+
// }
375+
assert!(bx.tcx().sess.target.endian == Endian::Little);
376+
let value_ptr =
377+
bx.phi(bx.type_ptr(), &[regsave_value_ptr, stack_value_ptr], &[from_regsave, from_stack]);
378+
return bx.load(layout.llvm_type(bx), value_ptr, layout.align.abi);
379+
}
380+
273381
pub(super) fn emit_va_arg<'ll, 'tcx>(
274382
bx: &mut Builder<'_, 'll, 'tcx>,
275383
addr: OperandRef<'tcx, &'ll Value>,
@@ -302,6 +410,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
302410
let indirect: bool = target_ty_size > 8 || !target_ty_size.is_power_of_two();
303411
emit_ptr_va_arg(bx, addr, target_ty, indirect, Align::from_bytes(8).unwrap(), false)
304412
}
413+
"xtensa" => emit_xtensa_va_arg(bx, addr, target_ty),
305414
// For all other architecture/OS combinations fall back to using
306415
// the LLVM va_arg instruction.
307416
// https://llvm.org/docs/LangRef.html#va-arg-instruction

‎compiler/rustc_codegen_ssa/src/codegen_attrs.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,13 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
542542
}
543543
});
544544

545+
// naked function MUST NOT be inlined! This attribute is required for the rust compiler itself,
546+
// but not for the code generation backend because at that point the naked function will just be
547+
// a declaration, with a definition provided in global assembly.
548+
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
549+
codegen_fn_attrs.inline = InlineAttr::Never;
550+
}
551+
545552
codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| {
546553
if !attr.has_name(sym::optimize) {
547554
return ia;
@@ -626,10 +633,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
626633
}
627634
}
628635

629-
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
630-
codegen_fn_attrs.inline = InlineAttr::Never;
631-
}
632-
633636
// Weak lang items have the same semantics as "std internal" symbols in the
634637
// sense that they're preserved through all our LTO passes and only
635638
// strippable by the linker.

‎compiler/rustc_codegen_ssa/src/mir/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ mod coverageinfo;
2020
pub mod debuginfo;
2121
mod intrinsic;
2222
mod locals;
23+
mod naked_asm;
2324
pub mod operand;
2425
pub mod place;
2526
mod rvalue;
@@ -176,6 +177,11 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
176177
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
177178
debug!("fn_abi: {:?}", fn_abi);
178179

180+
if cx.tcx().codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) {
181+
crate::mir::naked_asm::codegen_naked_asm::<Bx>(cx, &mir, instance);
182+
return;
183+
}
184+
179185
let debug_context = cx.create_function_debug_context(instance, fn_abi, llfn, mir);
180186

181187
let start_llbb = Bx::append_block(cx, llfn, "start");
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Failed to load comments.