Skip to content

Commit dfd5d41

Browse files
committed
Auto merge of rust-lang#135825 - jieyouxu:rollup-bske4m7, r=jieyouxu
Rollup of 10 pull requests Successful merges: - rust-lang#132232 (CI: build FreeBSD artifacts on FreeBSD 13.4) - rust-lang#135625 ([cfg_match] Document the use of expressions.) - rust-lang#135638 (Make it possible to build GCC on CI) - rust-lang#135648 (support wasm inline assembly in `naked_asm!`) - rust-lang#135707 (Shorten linker output even more when `--verbose` is not present) - rust-lang#135750 (Add an example of using `carrying_mul_add` to write wider multiplication) - rust-lang#135779 (CI: free disk on linux arm runner) - rust-lang#135793 (Ignore `mermaid.min.js`) - rust-lang#135810 (Add Kobzol on vacation) - rust-lang#135814 (ci: use ghcr buildkit image) r? `@ghost` `@rustbot` modify labels: rollup
2 parents cd805f0 + fde77e9 commit dfd5d41

File tree

25 files changed

+601
-50
lines changed

25 files changed

+601
-50
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ __pycache__/
8383
node_modules
8484
package-lock.json
8585
package.json
86+
/src/doc/rustc-dev-guide/mermaid.min.js
8687

8788
## Rustdoc GUI tests
8889
tests/rustdoc-gui/src/**.lock

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3537,6 +3537,7 @@ dependencies = [
35373537
"ar_archive_writer",
35383538
"arrayvec",
35393539
"bitflags",
3540+
"bstr",
35403541
"cc",
35413542
"either",
35423543
"itertools",

compiler/rustc_codegen_ssa/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ edition = "2021"
88
ar_archive_writer = "0.4.2"
99
arrayvec = { version = "0.7", default-features = false }
1010
bitflags = "2.4.1"
11+
bstr = "1.11.3"
1112
# Pinned so `cargo update` bumps don't cause breakage. Please also update the
1213
# `cc` in `rustc_llvm` if you update the `cc` here.
1314
cc = "=1.2.7"

compiler/rustc_codegen_ssa/src/back/command.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub(crate) struct Command {
1313
args: Vec<OsString>,
1414
env: Vec<(OsString, OsString)>,
1515
env_remove: Vec<OsString>,
16+
env_clear: bool,
1617
}
1718

1819
#[derive(Clone)]
@@ -36,7 +37,13 @@ impl Command {
3637
}
3738

3839
fn _new(program: Program) -> Command {
39-
Command { program, args: Vec::new(), env: Vec::new(), env_remove: Vec::new() }
40+
Command {
41+
program,
42+
args: Vec::new(),
43+
env: Vec::new(),
44+
env_remove: Vec::new(),
45+
env_clear: false,
46+
}
4047
}
4148

4249
pub(crate) fn arg<P: AsRef<OsStr>>(&mut self, arg: P) -> &mut Command {
@@ -79,6 +86,11 @@ impl Command {
7986
self
8087
}
8188

89+
pub(crate) fn env_clear(&mut self) -> &mut Command {
90+
self.env_clear = true;
91+
self
92+
}
93+
8294
fn _env_remove(&mut self, key: &OsStr) {
8395
self.env_remove.push(key.to_owned());
8496
}
@@ -106,6 +118,9 @@ impl Command {
106118
for k in &self.env_remove {
107119
ret.env_remove(k);
108120
}
121+
if self.env_clear {
122+
ret.env_clear();
123+
}
109124
ret
110125
}
111126

compiler/rustc_codegen_ssa/src/back/link.rs

+1
Original file line numberDiff line numberDiff line change
@@ -991,6 +991,7 @@ fn link_natively(
991991
command: cmd,
992992
escaped_output,
993993
verbose: sess.opts.verbose,
994+
sysroot_dir: sess.sysroot.clone(),
994995
};
995996
sess.dcx().emit_err(err);
996997
// If MSVC's `link.exe` was expected but the return code

compiler/rustc_codegen_ssa/src/errors.rs

+47-15
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ pub(crate) struct LinkingFailed<'a> {
351351
pub command: Command,
352352
pub escaped_output: String,
353353
pub verbose: bool,
354+
pub sysroot_dir: PathBuf,
354355
}
355356

356357
impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
@@ -364,6 +365,8 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
364365
if self.verbose {
365366
diag.note(format!("{:?}", self.command));
366367
} else {
368+
self.command.env_clear();
369+
367370
enum ArgGroup {
368371
Regular(OsString),
369372
Objects(usize),
@@ -398,26 +401,55 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
398401
args.push(ArgGroup::Regular(arg));
399402
}
400403
}
401-
self.command.args(args.into_iter().map(|arg_group| match arg_group {
402-
ArgGroup::Regular(arg) => arg,
403-
ArgGroup::Objects(n) => OsString::from(format!("<{n} object files omitted>")),
404-
ArgGroup::Rlibs(dir, rlibs) => {
405-
let mut arg = dir.into_os_string();
406-
arg.push("/{");
407-
let mut first = true;
408-
for rlib in rlibs {
409-
if !first {
410-
arg.push(",");
404+
let crate_hash = regex::bytes::Regex::new(r"-[0-9a-f]+\.rlib$").unwrap();
405+
self.command.args(args.into_iter().map(|arg_group| {
406+
match arg_group {
407+
// SAFETY: we are only matching on ASCII, not any surrogate pairs, so any replacements we do will still be valid.
408+
ArgGroup::Regular(arg) => unsafe {
409+
use bstr::ByteSlice;
410+
OsString::from_encoded_bytes_unchecked(
411+
arg.as_encoded_bytes().replace(
412+
self.sysroot_dir.as_os_str().as_encoded_bytes(),
413+
b"<sysroot>",
414+
),
415+
)
416+
},
417+
ArgGroup::Objects(n) => OsString::from(format!("<{n} object files omitted>")),
418+
ArgGroup::Rlibs(mut dir, rlibs) => {
419+
let is_sysroot_dir = match dir.strip_prefix(&self.sysroot_dir) {
420+
Ok(short) => {
421+
dir = Path::new("<sysroot>").join(short);
422+
true
423+
}
424+
Err(_) => false,
425+
};
426+
let mut arg = dir.into_os_string();
427+
arg.push("/{");
428+
let mut first = true;
429+
for mut rlib in rlibs {
430+
if !first {
431+
arg.push(",");
432+
}
433+
first = false;
434+
if is_sysroot_dir {
435+
// SAFETY: Regex works one byte at a type, and our regex will not match surrogate pairs (because it only matches ascii).
436+
rlib = unsafe {
437+
OsString::from_encoded_bytes_unchecked(
438+
crate_hash
439+
.replace(rlib.as_encoded_bytes(), b"-*")
440+
.into_owned(),
441+
)
442+
};
443+
}
444+
arg.push(rlib);
411445
}
412-
first = false;
413-
arg.push(rlib);
446+
arg.push("}.rlib");
447+
arg
414448
}
415-
arg.push("}");
416-
arg
417449
}
418450
}));
419451

420-
diag.note(format!("{:?}", self.command));
452+
diag.note(format!("{:?}", self.command).trim_start_matches("env -i").to_owned());
421453
diag.note("some arguments are omitted. use `--verbose` to show all linker arguments");
422454
}
423455

compiler/rustc_codegen_ssa/src/mir/naked_asm.rs

+168-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind};
12
use rustc_attr_parsing::InstructionSetAttr;
3+
use rustc_hir::def_id::DefId;
24
use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility};
35
use rustc_middle::mir::{Body, InlineAsmOperand};
4-
use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf};
5-
use rustc_middle::ty::{Instance, TyCtxt};
6-
use rustc_middle::{bug, ty};
6+
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf};
7+
use rustc_middle::ty::{Instance, Ty, TyCtxt};
8+
use rustc_middle::{bug, span_bug, ty};
79
use rustc_span::sym;
10+
use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
11+
use rustc_target::spec::WasmCAbi;
812

913
use crate::common;
1014
use crate::traits::{AsmCodegenMethods, BuilderMethods, GlobalAsmOperandRef, MiscCodegenMethods};
@@ -32,7 +36,8 @@ pub(crate) fn codegen_naked_asm<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
3236

3337
let item_data = cx.codegen_unit().items().get(&MonoItem::Fn(instance)).unwrap();
3438
let name = cx.mangled_name(instance);
35-
let (begin, end) = prefix_and_suffix(cx.tcx(), instance, &name, item_data);
39+
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
40+
let (begin, end) = prefix_and_suffix(cx.tcx(), instance, &name, item_data, fn_abi);
3641

3742
let mut template_vec = Vec::new();
3843
template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(begin.into()));
@@ -103,6 +108,7 @@ enum AsmBinaryFormat {
103108
Elf,
104109
Macho,
105110
Coff,
111+
Wasm,
106112
}
107113

108114
impl AsmBinaryFormat {
@@ -111,6 +117,8 @@ impl AsmBinaryFormat {
111117
Self::Coff
112118
} else if target.is_like_osx {
113119
Self::Macho
120+
} else if target.is_like_wasm {
121+
Self::Wasm
114122
} else {
115123
Self::Elf
116124
}
@@ -122,6 +130,7 @@ fn prefix_and_suffix<'tcx>(
122130
instance: Instance<'tcx>,
123131
asm_name: &str,
124132
item_data: &MonoItemData,
133+
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
125134
) -> (String, String) {
126135
use std::fmt::Write;
127136

@@ -169,7 +178,7 @@ fn prefix_and_suffix<'tcx>(
169178
}
170179
Linkage::LinkOnceAny | Linkage::LinkOnceODR | Linkage::WeakAny | Linkage::WeakODR => {
171180
match asm_binary_format {
172-
AsmBinaryFormat::Elf | AsmBinaryFormat::Coff => {
181+
AsmBinaryFormat::Elf | AsmBinaryFormat::Coff | AsmBinaryFormat::Wasm => {
173182
writeln!(w, ".weak {asm_name}")?;
174183
}
175184
AsmBinaryFormat::Macho => {
@@ -264,7 +273,161 @@ fn prefix_and_suffix<'tcx>(
264273
writeln!(end, "{}", arch_suffix).unwrap();
265274
}
266275
}
276+
AsmBinaryFormat::Wasm => {
277+
let section = link_section.unwrap_or(format!(".text.{asm_name}"));
278+
279+
writeln!(begin, ".section {section},\"\",@").unwrap();
280+
// wasm functions cannot be aligned, so skip
281+
write_linkage(&mut begin).unwrap();
282+
if let Visibility::Hidden = item_data.visibility {
283+
writeln!(begin, ".hidden {asm_name}").unwrap();
284+
}
285+
writeln!(begin, ".type {asm_name}, @function").unwrap();
286+
if !arch_prefix.is_empty() {
287+
writeln!(begin, "{}", arch_prefix).unwrap();
288+
}
289+
writeln!(begin, "{asm_name}:").unwrap();
290+
writeln!(
291+
begin,
292+
".functype {asm_name} {}",
293+
wasm_functype(tcx, fn_abi, instance.def_id())
294+
)
295+
.unwrap();
296+
297+
writeln!(end).unwrap();
298+
// .size is ignored for function symbols, so we can skip it
299+
writeln!(end, "end_function").unwrap();
300+
}
267301
}
268302

269303
(begin, end)
270304
}
305+
306+
/// The webassembly type signature for the given function.
307+
///
308+
/// Used by the `.functype` directive on wasm targets.
309+
fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id: DefId) -> String {
310+
let mut signature = String::with_capacity(64);
311+
312+
let ptr_type = match tcx.data_layout.pointer_size.bits() {
313+
32 => "i32",
314+
64 => "i64",
315+
other => bug!("wasm pointer size cannot be {other} bits"),
316+
};
317+
318+
// FIXME: remove this once the wasm32-unknown-unknown ABI is fixed
319+
// please also add `wasm32-unknown-unknown` back in `tests/assembly/wasm32-naked-fn.rs`
320+
// basically the commit introducing this comment should be reverted
321+
if let PassMode::Pair { .. } = fn_abi.ret.mode {
322+
let _ = WasmCAbi::Legacy;
323+
span_bug!(
324+
tcx.def_span(def_id),
325+
"cannot return a pair (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666"
326+
);
327+
}
328+
329+
let hidden_return = matches!(fn_abi.ret.mode, PassMode::Indirect { .. });
330+
331+
signature.push('(');
332+
333+
if hidden_return {
334+
signature.push_str(ptr_type);
335+
if !fn_abi.args.is_empty() {
336+
signature.push_str(", ");
337+
}
338+
}
339+
340+
let mut it = fn_abi.args.iter().peekable();
341+
while let Some(arg_abi) = it.next() {
342+
wasm_type(tcx, &mut signature, arg_abi, ptr_type, def_id);
343+
if it.peek().is_some() {
344+
signature.push_str(", ");
345+
}
346+
}
347+
348+
signature.push_str(") -> (");
349+
350+
if !hidden_return {
351+
wasm_type(tcx, &mut signature, &fn_abi.ret, ptr_type, def_id);
352+
}
353+
354+
signature.push(')');
355+
356+
signature
357+
}
358+
359+
fn wasm_type<'tcx>(
360+
tcx: TyCtxt<'tcx>,
361+
signature: &mut String,
362+
arg_abi: &ArgAbi<'_, Ty<'tcx>>,
363+
ptr_type: &'static str,
364+
def_id: DefId,
365+
) {
366+
match arg_abi.mode {
367+
PassMode::Ignore => { /* do nothing */ }
368+
PassMode::Direct(_) => {
369+
let direct_type = match arg_abi.layout.backend_repr {
370+
BackendRepr::Scalar(scalar) => wasm_primitive(scalar.primitive(), ptr_type),
371+
BackendRepr::Vector { .. } => "v128",
372+
BackendRepr::Memory { .. } => {
373+
// FIXME: remove this branch once the wasm32-unknown-unknown ABI is fixed
374+
let _ = WasmCAbi::Legacy;
375+
span_bug!(
376+
tcx.def_span(def_id),
377+
"cannot use memory args (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666"
378+
);
379+
}
380+
other => unreachable!("unexpected BackendRepr: {:?}", other),
381+
};
382+
383+
signature.push_str(direct_type);
384+
}
385+
PassMode::Pair(_, _) => match arg_abi.layout.backend_repr {
386+
BackendRepr::ScalarPair(a, b) => {
387+
signature.push_str(wasm_primitive(a.primitive(), ptr_type));
388+
signature.push_str(", ");
389+
signature.push_str(wasm_primitive(b.primitive(), ptr_type));
390+
}
391+
other => unreachable!("{other:?}"),
392+
},
393+
PassMode::Cast { pad_i32, ref cast } => {
394+
// For wasm, Cast is used for single-field primitive wrappers like `struct Wrapper(i64);`
395+
assert!(!pad_i32, "not currently used by wasm calling convention");
396+
assert!(cast.prefix[0].is_none(), "no prefix");
397+
assert_eq!(cast.rest.total, arg_abi.layout.size, "single item");
398+
399+
let wrapped_wasm_type = match cast.rest.unit.kind {
400+
RegKind::Integer => match cast.rest.unit.size.bytes() {
401+
..=4 => "i32",
402+
..=8 => "i64",
403+
_ => ptr_type,
404+
},
405+
RegKind::Float => match cast.rest.unit.size.bytes() {
406+
..=4 => "f32",
407+
..=8 => "f64",
408+
_ => ptr_type,
409+
},
410+
RegKind::Vector => "v128",
411+
};
412+
413+
signature.push_str(wrapped_wasm_type);
414+
}
415+
PassMode::Indirect { .. } => signature.push_str(ptr_type),
416+
}
417+
}
418+
419+
fn wasm_primitive(primitive: Primitive, ptr_type: &'static str) -> &'static str {
420+
match primitive {
421+
Primitive::Int(integer, _) => match integer {
422+
Integer::I8 | Integer::I16 | Integer::I32 => "i32",
423+
Integer::I64 => "i64",
424+
Integer::I128 => "i64, i64",
425+
},
426+
Primitive::Float(float) => match float {
427+
Float::F16 | Float::F32 => "f32",
428+
Float::F64 => "f64",
429+
Float::F128 => "i64, i64",
430+
},
431+
Primitive::Pointer(_) => ptr_type,
432+
}
433+
}

0 commit comments

Comments
 (0)