From d855d558f21bb9ed65c33d3ac7c143d91f3a9c9b Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Wed, 12 Aug 2026 17:17:16 +0200 Subject: [PATCH] perf: cranelift-codegen-meta: reduce llvm-lines in `strings.join(" ")` and iterators --- cranelift/codegen/meta/src/cdsl/formats.rs | 3 +- .../codegen/meta/src/cdsl/instructions.rs | 10 ++- cranelift/codegen/meta/src/cdsl/typevar.rs | 12 +-- cranelift/codegen/meta/src/display_join.rs | 35 +++++++++ cranelift/codegen/meta/src/gen_asm.rs | 60 ++++++++------- cranelift/codegen/meta/src/gen_inst.rs | 76 ++++++++++--------- cranelift/codegen/meta/src/gen_isle.rs | 32 +++++--- cranelift/codegen/meta/src/gen_settings.rs | 39 ++++++---- cranelift/codegen/meta/src/gen_types.rs | 33 ++++---- cranelift/codegen/meta/src/lib.rs | 1 + cranelift/codegen/meta/src/pulley.rs | 4 +- cranelift/srcgen/src/lib.rs | 2 +- 12 files changed, 192 insertions(+), 115 deletions(-) create mode 100644 cranelift/codegen/meta/src/display_join.rs diff --git a/cranelift/codegen/meta/src/cdsl/formats.rs b/cranelift/codegen/meta/src/cdsl/formats.rs index f9cec838cfa6..9be1c36dfb1a 100644 --- a/cranelift/codegen/meta/src/cdsl/formats.rs +++ b/cranelift/codegen/meta/src/cdsl/formats.rs @@ -1,4 +1,5 @@ use crate::cdsl::operands::OperandKind; +use crate::display_join::DisplayJoinedVecExt; use std::fmt; use std::rc::Rc; @@ -66,7 +67,7 @@ impl fmt::Display for InstructionFormat { .iter() .map(|field| format!("{}: {}", field.member, field.kind.rust_type)) .collect::>() - .join(", "); + .display_join(", "); fmt.write_fmt(format_args!( "{}(imms=({}), vals={}, blocks={}, raw_blocks={})", self.name, diff --git a/cranelift/codegen/meta/src/cdsl/instructions.rs b/cranelift/codegen/meta/src/cdsl/instructions.rs index e57f20786819..f100f450f0bd 100644 --- a/cranelift/codegen/meta/src/cdsl/instructions.rs +++ b/cranelift/codegen/meta/src/cdsl/instructions.rs @@ -6,6 +6,8 @@ use crate::cdsl::formats::InstructionFormat; use crate::cdsl::operands::Operand; use crate::cdsl::typevar::TypeVar; +use crate::display_join::DisplayJoinedVecExt; + pub(crate) type AllInstructions = Vec; pub(crate) struct InstructionGroupBuilder<'all_inst> { @@ -102,8 +104,8 @@ impl fmt::Display for InstructionContent { .iter() .map(|op| op.name) .collect::>() - .join(", "); - fmt.write_str(&operands_out)?; + .display_join(", "); + operands_out.fmt(fmt)?; fmt.write_str(" = ")?; } @@ -115,9 +117,9 @@ impl fmt::Display for InstructionContent { .iter() .map(|op| op.name) .collect::>() - .join(", "); + .display_join(", "); fmt.write_str(" ")?; - fmt.write_str(&operands_in)?; + operands_in.fmt(fmt)?; } Ok(()) diff --git a/cranelift/codegen/meta/src/cdsl/typevar.rs b/cranelift/codegen/meta/src/cdsl/typevar.rs index 61f31d9dbf50..ecbe6315a6e2 100644 --- a/cranelift/codegen/meta/src/cdsl/typevar.rs +++ b/cranelift/codegen/meta/src/cdsl/typevar.rs @@ -5,6 +5,8 @@ use std::hash; use std::ops; use std::rc::Rc; +use crate::display_join::DisplayJoinedVecExt; + use crate::cdsl::types::{LaneType, ValueType}; const MAX_LANES: u16 = 256; @@ -532,29 +534,29 @@ impl fmt::Debug for TypeSet { if !self.lanes.is_empty() { subsets.push(format!( "lanes={{{}}}", - Vec::from_iter(self.lanes.iter().map(|x| x.to_string())).join(", ") + Vec::from_iter(self.lanes.iter().map(|x| x.to_string())).display_join(", ") )); } if !self.dynamic_lanes.is_empty() { subsets.push(format!( "dynamic_lanes={{{}}}", - Vec::from_iter(self.dynamic_lanes.iter().map(|x| x.to_string())).join(", ") + Vec::from_iter(self.dynamic_lanes.iter().map(|x| x.to_string())).display_join(", ") )); } if !self.ints.is_empty() { subsets.push(format!( "ints={{{}}}", - Vec::from_iter(self.ints.iter().map(|x| x.to_string())).join(", ") + Vec::from_iter(self.ints.iter().map(|x| x.to_string())).display_join(", ") )); } if !self.floats.is_empty() { subsets.push(format!( "floats={{{}}}", - Vec::from_iter(self.floats.iter().map(|x| x.to_string())).join(", ") + Vec::from_iter(self.floats.iter().map(|x| x.to_string())).display_join(", ") )); } - write!(fmt, "{})", subsets.join(", "))?; + write!(fmt, "{})", subsets.display_join(", "))?; Ok(()) } } diff --git a/cranelift/codegen/meta/src/display_join.rs b/cranelift/codegen/meta/src/display_join.rs new file mode 100644 index 000000000000..3b40d6d51897 --- /dev/null +++ b/cranelift/codegen/meta/src/display_join.rs @@ -0,0 +1,35 @@ +/// Joins strings, just like `.join(" ")` but with [`core::fmt::Display`] +pub(crate) struct DisplayJoined<'a, S: AsRef>(pub &'static str, pub &'a [S]); + +impl<'a, S: AsRef> core::fmt::Display for DisplayJoined<'a, S> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut sep = false; + for s in self.1 { + if sep { + f.write_str(self.0)?; + } + sep = true; + f.write_str(s.as_ref())?; + } + Ok(()) + } +} + +/// Joins strings, just like `.join(" ")` but with [`core::fmt::Display`] +pub(crate) struct DisplayJoinedVec>(pub &'static str, pub Vec); + +impl> core::fmt::Display for DisplayJoinedVec { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + DisplayJoined(self.0, &self.1).fmt(f) + } +} + +pub(crate) trait DisplayJoinedVecExt> { + /// Joins strings, just like `.join(" ")` but with [`core::fmt::Display`] + fn display_join(self, sep: &'static str) -> DisplayJoinedVec; +} +impl> DisplayJoinedVecExt for Vec { + fn display_join(self, sep: &'static str) -> DisplayJoinedVec { + DisplayJoinedVec(sep, self) + } +} diff --git a/cranelift/codegen/meta/src/gen_asm.rs b/cranelift/codegen/meta/src/gen_asm.rs index 8a70b2689524..6e77f57d8b5a 100644 --- a/cranelift/codegen/meta/src/gen_asm.rs +++ b/cranelift/codegen/meta/src/gen_asm.rs @@ -5,6 +5,8 @@ use cranelift_assembler_x64_meta::dsl::{ }; use cranelift_srcgen::{Formatter, fmtln}; +use crate::display_join::DisplayJoinedVecExt; + /// This factors out use of the assembler crate name. const ASM: &str = "cranelift_assembler_x64"; @@ -110,17 +112,16 @@ fn generate_macro_inst_fn(f: &mut Formatter, inst: &Inst) { .iter() .filter(|o| o.mutability.is_write()) .collect::>(); - let rust_params = operands + let mut rust_params = operands .iter() .filter(|o| is_raw_operand_param(o)) .map(|o| format!("{}: {}", o.location, rust_param_raw(o))) - .chain(if inst.has_trap { - Some(format!("trap: &TrapCode")) - } else { - None - }) - .collect::>() - .join(", "); + .collect::>(); + if inst.has_trap { + rust_params.push("trap: &TrapCode".to_string()); + } + let rust_params = rust_params.display_join(", "); + f.add_block( &format!("fn x64_{struct_name}_raw(&mut self, {rust_params}) -> AssemblerOutputs"), |f| { @@ -137,7 +138,7 @@ fn generate_macro_inst_fn(f: &mut Formatter, inst: &Inst) { if inst.has_trap { args.push(format!("{ASM}::TrapCode(trap.as_raw())")); } - let args = args.join(", "); + let args = args.display_join(", "); f.empty_line(); f.comment("Build the instruction."); @@ -179,12 +180,12 @@ fn generate_macro_inst_fn(f: &mut Formatter, inst: &Inst) { } RegMem(rm) => { let (ty, var) = ty_var_of_reg(rm); - f.add_block(&format!("match {rm}"), |f| { - f.add_block(&format!("{ASM}::{ty}Mem::{ty}(reg) => "), |f| { + f.add_block(format_args!("match {rm}"), |f| { + f.add_block(format_args!("{ASM}::{ty}Mem::{ty}(reg) => "), |f| { fmtln!(f, "let {var} = reg.{};", access_reg(op)); fmtln!(f, "AssemblerOutputs::Ret{ty} {{ inst, {var} }} "); }); - f.add_block(&format!("{ASM}::{ty}Mem::Mem(_) => "), |f| { + f.add_block(format_args!("{ASM}::{ty}Mem::Mem(_) => "), |f| { fmtln!(f, "AssemblerOutputs::SideEffect {{ inst }} "); }); }); @@ -548,12 +549,12 @@ fn generate_isle_inst_decls(f: &mut Formatter, inst: &Inst) { .iter() .filter(|o| is_raw_operand_param(o)) .collect::>(); - let raw_param_tys = params - .iter() - .map(|o| isle_param_raw(o)) - .chain(trap_type.clone()) - .collect::>() - .join(" "); + let mut raw_param_tys = params.iter().map(|o| isle_param_raw(o)).collect::>(); + if let Some(trap_type) = &trap_type { + raw_param_tys.push(trap_type.clone()); + } + let raw_param_tys = raw_param_tys.display_join(" "); + fmtln!(f, "(decl {raw_name} ({raw_param_tys}) AssemblerOutputs)"); fmtln!(f, "(extern constructor {raw_name} {raw_name})"); @@ -584,18 +585,22 @@ fn generate_isle_inst_decls(f: &mut Formatter, inst: &Inst) { } } assert!(implicit_params.len() <= 1); - let param_tys = explicit_params + let mut param_tys = explicit_params .iter() .map(|o| isle_param_for_ctor(o, ctor)) - .chain(trap_type.clone()) - .collect::>() - .join(" "); - let param_names = explicit_params + .collect::>(); + if let Some(trap_type) = &trap_type { + param_tys.push(trap_type.clone()); + } + let param_tys = param_tys.display_join(" "); + let mut param_names = explicit_params .iter() .map(|o| o.location.to_string()) - .chain(trap_name.clone()) - .collect::>() - .join(" "); + .collect::>(); + if let Some(trap_name) = &trap_name { + param_names.push(trap_name.clone()); + } + let param_names = param_names.display_join(" "); let convert = ctor.conversion_constructor(); // Generate implicit parameters to the `*_raw` constructor. Currently @@ -619,7 +624,7 @@ fn generate_isle_inst_decls(f: &mut Formatter, inst: &Inst) { } }) .collect::>() - .join(" "); + .display_join(" "); fmtln!(f, "(decl {rule_name} ({param_tys}) {result_ty})"); fmtln!( @@ -638,6 +643,7 @@ fn generate_isle_inst_decls(f: &mut Formatter, inst: &Inst) { .iter() .any(|o| matches!(o.location.reg_class(), Some(RegClass::Xmm))) ); + let param_tys = param_tys.to_string(); let param_tys = if alternate.feature == Feature::avx { param_tys.replace("Aligned", "") } else { diff --git a/cranelift/codegen/meta/src/gen_inst.rs b/cranelift/codegen/meta/src/gen_inst.rs index 7acf965885c9..f6af5a01d34f 100644 --- a/cranelift/codegen/meta/src/gen_inst.rs +++ b/cranelift/codegen/meta/src/gen_inst.rs @@ -5,6 +5,7 @@ use crate::cdsl::formats::InstructionFormat; use crate::cdsl::instructions::{AllInstructions, Instruction}; use crate::cdsl::operands::{Operand, OperandKindFields}; use crate::cdsl::typevar::{TypeSet, TypeVar}; +use crate::display_join::DisplayJoinedVecExt; use crate::unique_table::{UniqueSeqTable, UniqueTable}; use cranelift_codegen_shared::constant_hash; use cranelift_srcgen::{Formatter, Language, Match, error, fmtln}; @@ -66,7 +67,7 @@ fn gen_instruction_data(formats: &[Rc], fmt: &mut Formatter) fmt.line("#[allow(missing_docs, reason = \"generated code\")]"); fmt.add_block("pub enum InstructionData", |fmt| { for format in formats { - fmt.add_block(&format!("{}", format.name), |fmt| { + fmt.add_block(format_args!("{}", format.name), |fmt| { fmt.line("opcode: Opcode,"); if format.has_value_list { fmt.line("args: ValueList,"); @@ -114,7 +115,7 @@ fn gen_arguments_method(formats: &[Rc], fmt: &mut Formatter, ("arguments", "", "core::slice::from_ref", "as_slice") }; - fmt.add_block(&format!( + fmt.add_block(format_args!( "pub fn {method}<'a>(&'a {mut_}self, pool: &'a {mut_}ir::ValueListPool) -> &'a {mut_}[Value]"), |fmt| { @@ -268,9 +269,9 @@ fn gen_instruction_data_impl(formats: &[Rc], fmt: &mut Format members.push(field.member); } - let pat1 = members.iter().map(|x| format!("{x}: ref {x}1")).collect::>().join(", "); - let pat2 = members.iter().map(|x| format!("{x}: ref {x}2")).collect::>().join(", "); - fmt.add_block(&format!("({name} {{ {pat1} }}, {name} {{ {pat2} }}) => "), |fmt| { + let pat1 = members.iter().map(|&x| format!("{x}: ref {x}1")).collect::>().display_join(", "); + let pat2 = members.iter().map(|&x| format!("{x}: ref {x}2")).collect::>().display_join(", "); + fmt.add_block(format_args!("({name} {{ {pat1} }}, {name} {{ {pat2} }}) => "), |fmt| { fmt.line("opcode1 == opcode2"); for field in &format.imm_fields { fmtln!(fmt, "&& {}1 == {}2", field.member, field.member); @@ -344,9 +345,9 @@ fn gen_instruction_data_impl(formats: &[Rc], fmt: &mut Format for field in &format.imm_fields { members.push(field.member); } - let members = members.join(", "); + let members = members.display_join(", "); - fmt.add_block(&format!("{name}{{{members}}} => "), |fmt| { + fmt.add_block(format_args!("{name}{{{members}}} => "), |fmt| { fmt.line("::core::hash::Hash::hash( &::core::mem::discriminant(self), state);"); fmt.line("::core::hash::Hash::hash(&opcode, state);"); for field in &format.imm_fields { @@ -354,14 +355,14 @@ fn gen_instruction_data_impl(formats: &[Rc], fmt: &mut Format } fmtln!(fmt, "::core::hash::Hash::hash(&{}, state);", len); if let Some(args) = args { - fmt.add_block(&format!("for &arg in {args}"), |fmt| { + fmt.add_block(format_args!("for &arg in {args}"), |fmt| { fmtln!(fmt, "::core::hash::Hash::hash(&arg, state);"); }); } if let Some((blocks, len)) = blocks { fmtln!(fmt, "::core::hash::Hash::hash(&{len}, state);"); - fmt.add_block(&format!("for &block in {blocks}"), |fmt| { + fmt.add_block(format_args!("for &block in {blocks}"), |fmt| { fmtln!(fmt, "::core::hash::Hash::hash(&block.block(pool), state);"); fmt.add_block("for arg in block.args(pool)", |fmt| { fmtln!(fmt, "::core::hash::Hash::hash(&arg, state);"); @@ -420,10 +421,10 @@ fn gen_instruction_data_impl(formats: &[Rc], fmt: &mut Format for field in &format.imm_fields { members.push(field.member); } - let members = members.join(", "); + let members = members.display_join(", "); - fmt.add_block(&format!("{name}{{{members}}} => "),|fmt| { - fmt.add_block(&format!("Self::{}", format.name), |fmt| { + fmt.add_block(format_args!("{name}{{{members}}} => "),|fmt| { + fmt.add_block(format_args!("Self::{}", format.name), |fmt| { fmtln!(fmt, "opcode,"); if format.has_value_list { @@ -500,10 +501,10 @@ fn gen_instruction_data_impl(formats: &[Rc], fmt: &mut Format for field in &format.imm_fields { members.push(field.member); } - let members = members.join(", "); + let members = members.display_join(", "); - fmt.add_block(&format!("{name}{{{members}}} => "), |fmt| { - fmt.add_block(&format!("Self::{}", format.name), |fmt| { + fmt.add_block(format_args!("{name}{{{members}}} => "), |fmt| { + fmt.add_block(format_args!("Self::{}", format.name), |fmt| { fmtln!(fmt, "opcode,"); if format.has_value_list { @@ -513,8 +514,8 @@ fn gen_instruction_data_impl(formats: &[Rc], fmt: &mut Format } else if format.num_value_operands > 0 { let maps = (0..format.num_value_operands) .map(|i| format!("mapper.map_value(args[{i}])")) - .collect::>() - .join(", "); + .collect::>() + .display_join(", "); fmtln!(fmt, "args: [{maps}],"); } @@ -583,7 +584,7 @@ fn gen_bool_accessor bool>( fmt: &mut Formatter, ) { fmt.doc_comment(doc); - fmt.add_block(&format!("pub fn {name}(self) -> bool"), |fmt| { + fmt.add_block(format_args!("pub fn {name}(self) -> bool"), |fmt| { let mut m = Match::new("self"); for inst in all_inst.iter() { if get_attr(inst) { @@ -832,7 +833,7 @@ fn iterable_to_string>(iterable: T) - .into_iter() .map(|x| x.to_string()) .collect::>() - .join(", "); + .display_join(", "); format!("{{{elems}}}") } @@ -938,18 +939,18 @@ fn gen_type_constraints(all_inst: &AllInstructions, fmt: &mut Formatter) { let requires_typevar_operand = use_typevar_operand && !use_result; fmt.comment( - format!("{}: fixed_results={}, use_typevar_operand={}, requires_typevar_operand={}, fixed_values={}", + format_args!("{}: fixed_results={}, use_typevar_operand={}, requires_typevar_operand={}, fixed_values={}", inst.camel_name, fixed_results, use_typevar_operand, requires_typevar_operand, fixed_values) ); - fmt.comment(format!("Constraints=[{}]", constraints + fmt.comment(format_args!("Constraints=[{}]", constraints .iter() .map(|x| format!("'{x}'")) .collect::>() - .join(", "))); + .display_join(", "))); if let Some(poly) = &inst.polymorphic_info { fmt.comment(format_args!("Polymorphic over {}", typeset_to_string(poly.ctrl_typevar.get_raw_typeset()))); } @@ -1011,7 +1012,7 @@ fn gen_member_inits(format: &InstructionFormat, fmt: &mut Formatter) { for i in 0..format.num_value_operands { args.push(format!("arg{i}")); } - fmtln!(fmt, "args: [{}],", args.join(", ")); + fmtln!(fmt, "args: [{}],", args.display_join(", ")); } // Block operands @@ -1023,7 +1024,7 @@ fn gen_member_inits(format: &InstructionFormat, fmt: &mut Formatter) { for i in 0..n { blocks.push(format!("block{i}")); } - fmtln!(fmt, "blocks: [{}],", blocks.join(", ")); + fmtln!(fmt, "blocks: [{}],", blocks.display_join(", ")); } } @@ -1073,7 +1074,7 @@ fn gen_format_constructor(format: &InstructionFormat, fmt: &mut Formatter) { let proto = format!( "{}({}) -> (Inst, &'f mut ir::DataFlowGraph)", format.name, - args.join(", ") + args.display_join(", ") ); let imms_need_masking = format @@ -1083,9 +1084,9 @@ fn gen_format_constructor(format: &InstructionFormat, fmt: &mut Formatter) { fmt.doc_comment(format.to_string()); fmt.line("#[allow(non_snake_case, reason = \"generated code\")]"); - fmt.add_block(&format!("fn {proto}"), |fmt| { + fmt.add_block(format_args!("fn {proto}"), |fmt| { // Generate the instruction data. - fmt.add_block(&format!( + fmt.add_block(format_args!( "let{} data = ir::InstructionData::{}", if imms_need_masking { " mut" } else { "" }, format.name @@ -1195,11 +1196,14 @@ fn gen_inst_builder(inst: &Instruction, format: &InstructionFormat, fmt: &mut Fo let rtype = match inst.value_results.len() { 0 => "Inst".into(), 1 => "Value".into(), - _ => format!("({})", vec!["Value"; inst.value_results.len()].join(", ")), + _ => format!( + "({})", + vec!["Value"; inst.value_results.len()].display_join(", ") + ), }; let tmpl = if !tmpl_types.is_empty() { - format!("<{}>", tmpl_types.join(", ")) + format!("<{}>", tmpl_types.display_join(", ")) } else { "".into() }; @@ -1208,7 +1212,7 @@ fn gen_inst_builder(inst: &Instruction, format: &InstructionFormat, fmt: &mut Fo "{}{}({}) -> {}", inst.snake_name(), tmpl, - args.join(", "), + args.display_join(", "), rtype ); @@ -1231,7 +1235,7 @@ fn gen_inst_builder(inst: &Instruction, format: &InstructionFormat, fmt: &mut Fo } fmt.line("#[allow(non_snake_case, reason = \"generated code\")]"); - fmt.add_block(&format!("fn {proto}"), |fmt| { + fmt.add_block(format_args!("fn {proto}"), |fmt| { // Convert all of the `Into<>` arguments. for arg in into_args { fmtln!(fmt, "let {} = {}.into();", arg, arg); @@ -1311,7 +1315,7 @@ fn gen_inst_builder(inst: &Instruction, format: &InstructionFormat, fmt: &mut Fo } // Call to the format constructor, - let fcall = format!("self.{}({})", format.name, args.join(", ")); + let fcall = format!("self.{}({})", format.name, args.display_join(", ")); fmtln!(fmt, "let (inst, dfg) = {};", fcall); fmtln!( @@ -1340,7 +1344,7 @@ fn gen_inst_builder(inst: &Instruction, format: &InstructionFormat, fmt: &mut Fo .enumerate() .map(|(i, _)| format!("results[{i}]")) .collect::>() - .join(", ") + .display_join(", ") ); } }); @@ -1436,7 +1440,7 @@ fn gen_one_imm_inst_builder( let proto = format!( "{}{suffix}>({}) -> Value", inst.snake_name(), - args.join(", "), + args.display_join(", "), ); let extends = if signed { @@ -1461,7 +1465,7 @@ fn gen_one_imm_inst_builder( fmtln!(fmt, "#[deprecated(note = \"{note}\")]"); } fmt.line("#[allow(non_snake_case, reason = \"generated code\")]"); - fmt.add_block(&format!("fn {proto}"), |fmt| { + fmt.add_block(format_args!("fn {proto}"), |fmt| { fmtln!(fmt, "let {imm_name} = {imm_name}.into();"); fmtln!( fmt, @@ -1476,7 +1480,7 @@ fn gen_one_imm_inst_builder( .iter() .map(|op| op.name) .collect::>() - .join(", "); + .display_join(", "); fmtln!(fmt, "self.{}({call_args})", inst.snake_name()); }); } diff --git a/cranelift/codegen/meta/src/gen_isle.rs b/cranelift/codegen/meta/src/gen_isle.rs index 6518356a719e..7a0c3b564b34 100644 --- a/cranelift/codegen/meta/src/gen_isle.rs +++ b/cranelift/codegen/meta/src/gen_isle.rs @@ -1,5 +1,6 @@ use crate::cdsl::formats::InstructionFormat; use crate::cdsl::instructions::AllInstructions; +use crate::display_join::DisplayJoinedVecExt; use crate::error; use cranelift_srcgen::{Formatter, Language, fmtln}; use std::{borrow::Cow, cmp::Ordering, rc::Rc}; @@ -93,7 +94,10 @@ fn gen_common_isle( fmt, "(decl value_array_{} ({}) ValueArray{})", n, - (0..n).map(|_| "Value").collect::>().join(" "), + (0..n) + .map(|_| "Value") + .collect::>() + .display_join(" "), n ); fmtln!( @@ -129,7 +133,10 @@ fn gen_common_isle( fmt, "(decl block_array_{0} ({1}) BlockArray{0})", n, - (0..n).map(|_| "BlockCall").collect::>().join(" ") + (0..n) + .map(|_| "BlockCall") + .collect::>() + .display_join(" ") ); fmtln!( @@ -256,7 +263,7 @@ fn gen_common_isle( } }) .collect::>() - .join(" "), + .display_join(" "), ret_ty ); fmtln!(fmt, "(extractor"); @@ -270,7 +277,7 @@ fn gen_common_isle( .iter() .map(|o| { o.name }) .collect::>() - .join(" ") + .display_join(" ") ); let mut s = format!( @@ -312,7 +319,7 @@ fn gen_common_isle( &mut s, " (unwrap_head_value_list_{} {} {})", values.len(), - values.join(" "), + values.display_join(" "), varargs ) .unwrap(); @@ -332,7 +339,7 @@ fn gen_common_isle( .map(|o| o.name) .collect::>(); assert_eq!(values.len(), inst.format.num_value_operands); - let values = values.join(" "); + let values = values.display_join(" "); write!( &mut s, " (value_array_{} {})", @@ -354,8 +361,11 @@ fn gen_common_isle( if block_operands.len() == 1 { write!(&mut s, " {}", block_operands[0].name).unwrap(); } else { - let blocks: Vec<_> = block_operands.iter().map(|o| o.name).collect(); - let blocks = blocks.join(" "); + let blocks = block_operands + .iter() + .map(|o| o.name) + .collect::>() + .display_join(" "); write!( &mut s, " (block_array_{} {})", @@ -403,7 +413,7 @@ fn gen_common_isle( .iter() .map(|o| o.name) .collect::>() - .join(" ") + .display_join(" ") ); fmt.indent(|fmt| { let mut s = format!( @@ -446,7 +456,7 @@ fn gen_common_isle( .map(|o| o.name) .collect::>(); assert_eq!(values.len(), inst.format.num_value_operands); - let values = values.join(" "); + let values = values.display_join(" "); write!( &mut s, " (value_array_{}_ctor {})", @@ -469,7 +479,7 @@ fn gen_common_isle( &mut s, " (block_array_{} {})", inst.format.num_block_operands, - blocks.join(" ") + blocks.display_join(" ") ) .unwrap(); } diff --git a/cranelift/codegen/meta/src/gen_settings.rs b/cranelift/codegen/meta/src/gen_settings.rs index 2c06e16dbb73..60b76582492f 100644 --- a/cranelift/codegen/meta/src/gen_settings.rs +++ b/cranelift/codegen/meta/src/gen_settings.rs @@ -8,6 +8,8 @@ use cranelift_codegen_shared::constant_hash::simple_hash; use cranelift_srcgen::{Formatter, Language, Match, error, fmtln}; use std::collections::HashMap; +use crate::display_join::DisplayJoinedVecExt; + pub(crate) enum ParentGroup { None, Shared, @@ -25,7 +27,7 @@ fn gen_constructor(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatte fmt, "#[allow(unused_variables, reason = \"generated code\")]" ); - fmt.add_block(&format!("pub fn new({args}) -> Self"), |fmt| { + fmt.add_block(format_args!("pub fn new({args}) -> Self"), |fmt| { fmtln!(fmt, "let bvec = builder.state_for(\"{}\");", group.name); fmtln!( fmt, @@ -78,7 +80,7 @@ fn gen_enum_all(name: &str, values: &[&'static str], fmt: &mut Formatter) { "/// Returns a slice with all possible [{}] values.", name ); - fmt.add_block(&format!("pub fn all() -> &'static [{name}]"), |fmt| { + fmt.add_block(format_args!("pub fn all() -> &'static [{name}]"), |fmt| { fmtln!(fmt, "&["); fmt.indent(|fmt| { for v in values.iter() { @@ -91,7 +93,7 @@ fn gen_enum_all(name: &str, values: &[&'static str], fmt: &mut Formatter) { /// Emit Display and FromStr implementations for enum settings. fn gen_to_and_from_str(name: &str, values: &[&'static str], fmt: &mut Formatter) { - fmt.add_block(&format!("impl fmt::Display for {name}"), |fmt| { + fmt.add_block(format_args!("impl fmt::Display for {name}"), |fmt| { fmt.add_block( "fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result", |fmt| { @@ -105,7 +107,7 @@ fn gen_to_and_from_str(name: &str, values: &[&'static str], fmt: &mut Formatter) ); }); - fmt.add_block(&format!("impl core::str::FromStr for {name}"), |fmt| { + fmt.add_block(format_args!("impl core::str::FromStr for {name}"), |fmt| { fmtln!(fmt, "type Err = ();"); fmt.add_block("fn from_str(s: &str) -> Result", |fmt| { fmt.add_block("match s", |fmt| { @@ -129,14 +131,14 @@ fn gen_enum_types(group: &SettingGroup, fmt: &mut Formatter) { fmt.doc_comment(format!("Values for `{}.{}`.", group.name, setting.name)); fmtln!(fmt, "#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]"); - fmt.add_block(&format!("pub enum {name}"), |fmt| { + fmt.add_block(format_args!("pub enum {name}"), |fmt| { for v in values.iter() { fmt.doc_comment(format!("`{v}`.")); fmtln!(fmt, "{},", camel_case(v)); } }); - fmt.add_block(&format!("impl {name}"), |fmt| { + fmt.add_block(format_args!("impl {name}"), |fmt| { gen_enum_all(&name, values, fmt); }); @@ -151,9 +153,12 @@ fn gen_getter(setting: &Setting, fmt: &mut Formatter) { SpecificSetting::Bool(BoolSetting { predicate_number, .. }) => { - fmt.add_block(&format!("pub fn {}(&self) -> bool", setting.name), |fmt| { - fmtln!(fmt, "self.numbered_predicate({})", predicate_number); - }); + fmt.add_block( + format_args!("pub fn {}(&self) -> bool", setting.name), + |fmt| { + fmtln!(fmt, "self.numbered_predicate({})", predicate_number); + }, + ); } SpecificSetting::Enum(ref values) => { let ty = camel_case(setting.name); @@ -170,9 +175,12 @@ fn gen_getter(setting: &Setting, fmt: &mut Formatter) { ); } SpecificSetting::Num(_) => { - fmt.add_block(&format!("pub fn {}(&self) -> u8", setting.name), |fmt| { - fmtln!(fmt, "self.bytes[{}]", setting.byte_offset); - }); + fmt.add_block( + format_args!("pub fn {}(&self) -> u8", setting.name), + |fmt| { + fmtln!(fmt, "self.bytes[{}]", setting.byte_offset); + }, + ); } } } @@ -320,7 +328,10 @@ fn gen_descriptors(group: &SettingGroup, fmt: &mut Formatter) { fmt.comment(format_args!( "{}: {}", preset.name, - preset.setting_names(group).collect::>().join(", ") + preset + .setting_names(group) + .collect::>() + .display_join(", ") )); for (mask, value) in preset.layout(group) { fmtln!(fmt, "(0b{:08b}, 0b{:08b}),", mask, value); @@ -337,7 +348,7 @@ fn gen_template(group: &SettingGroup, fmt: &mut Formatter) { } let default_bytes: Vec = default_bytes.iter().map(|x| format!("{x:#04x}")).collect(); - let default_bytes_str = default_bytes.join(", "); + let default_bytes_str = default_bytes.display_join(", "); fmt.add_block( "static TEMPLATE: detail::Template = detail::Template", diff --git a/cranelift/codegen/meta/src/gen_types.rs b/cranelift/codegen/meta/src/gen_types.rs index 78a89593277b..a44cf927b59d 100644 --- a/cranelift/codegen/meta/src/gen_types.rs +++ b/cranelift/codegen/meta/src/gen_types.rs @@ -22,33 +22,36 @@ fn emit_type(ty: &cdsl_types::ValueType, fmt: &mut Formatter) { /// Emit definition for all vector types with `bits` total size. fn emit_vectors(bits: u64, fmt: &mut Formatter) { let vec_size: u64 = bits / 8; - for vec in cdsl_types::ValueType::all_lane_types() - .map(|ty| (ty, cdsl_types::ValueType::from(ty).membytes())) - .filter(|&(_, lane_size)| lane_size != 0 && lane_size < vec_size) - .map(|(ty, lane_size)| (ty, vec_size / lane_size)) - .map(|(ty, lanes)| cdsl_types::VectorType::new(ty, lanes)) - { - emit_type(&cdsl_types::ValueType::from(vec), fmt); + + for ty in cdsl_types::ValueType::all_lane_types() { + let lane_size = cdsl_types::ValueType::from(ty).membytes(); + if lane_size != 0 && lane_size < vec_size { + let lanes = vec_size / lane_size; + let vec_type = cdsl_types::VectorType::new(ty, lanes); + emit_type(&cdsl_types::ValueType::from(vec_type), fmt); + } } } /// Emit definition for all dynamic vector types with `bits` total size. fn emit_dynamic_vectors(bits: u64, fmt: &mut Formatter) { let vec_size: u64 = bits / 8; - for vec in cdsl_types::ValueType::all_lane_types() - .map(|ty| (ty, cdsl_types::ValueType::from(ty).membytes())) - .filter(|&(_, lane_size)| lane_size != 0 && lane_size < vec_size) - .map(|(ty, lane_size)| (ty, vec_size / lane_size)) - .map(|(ty, lanes)| cdsl_types::DynamicVectorType::new(ty, lanes)) - { - emit_type(&cdsl_types::ValueType::from(vec), fmt); + + for ty in cdsl_types::ValueType::all_lane_types() { + let lane_size = cdsl_types::ValueType::from(ty).membytes(); + if lane_size != 0 && lane_size < vec_size { + let lanes = vec_size / lane_size; + let vec_type = cdsl_types::DynamicVectorType::new(ty, lanes); + emit_type(&cdsl_types::ValueType::from(vec_type), fmt); + } } } /// Emit types using the given formatter object. fn emit_types(fmt: &mut Formatter) { // Emit all of the lane types, such integers, floats, and booleans. - for ty in cdsl_types::ValueType::all_lane_types().map(cdsl_types::ValueType::from) { + for ty in cdsl_types::ValueType::all_lane_types() { + let ty = cdsl_types::ValueType::from(ty); emit_type(&ty, fmt); } diff --git a/cranelift/codegen/meta/src/lib.rs b/cranelift/codegen/meta/src/lib.rs index d229b68c78b3..b2297cb5d326 100644 --- a/cranelift/codegen/meta/src/lib.rs +++ b/cranelift/codegen/meta/src/lib.rs @@ -17,6 +17,7 @@ mod gen_settings; mod gen_types; mod constant_hash; +mod display_join; mod shared; mod unique_table; diff --git a/cranelift/codegen/meta/src/pulley.rs b/cranelift/codegen/meta/src/pulley.rs index 4af01ae3ceea..224a4a9aa5e3 100644 --- a/cranelift/codegen/meta/src/pulley.rs +++ b/cranelift/codegen/meta/src/pulley.rs @@ -1,6 +1,8 @@ use cranelift_srcgen::error::Error; use std::path::Path; +use crate::display_join::DisplayJoinedVecExt; + struct Inst<'a> { snake_name: &'a str, name: &'a str, @@ -391,7 +393,7 @@ pub fn generate_isle(filename: &str, out_dir: &Path) -> Result<(), Error> { } isle.push_str(") "); rule.push_str(")"); - let ops = ops.join(" "); + let ops = ops.display_join(" "); match &results[..] { [result] => { isle.push_str(result); diff --git a/cranelift/srcgen/src/lib.rs b/cranelift/srcgen/src/lib.rs index 8a570a213d38..7e3bc4fb620b 100644 --- a/cranelift/srcgen/src/lib.rs +++ b/cranelift/srcgen/src/lib.rs @@ -191,7 +191,7 @@ impl Formatter { /// Add a brace-delimited block that begins with `start`: i.e., ` { /// }`. This properly indents the contents of the block. - pub fn add_block T>(&mut self, start: &str, f: F) -> T { + pub fn add_block T>(&mut self, start: impl Display, f: F) -> T { assert!(matches!(self.lang, Language::Rust)); self.line(format_args!("{start} {{")); let ret = self.indent(f);