Skip to content

Commit 10d3a22

Browse files
authored
Cranelift: Generate an InstructionData::map method (#11176)
* Cranelift: Generate an `InstructionData::map` method This allows you to map some functions, described by the given `InstructionMapper`, over each of the entitities in an instruction, producing a new `InstructionData`. I intend to use this as part of an inliner API for Cranelift that I am developing as part of prototyping [Wasmtime's compile-time builtins](bytecodealliance/rfcs#43). * cargo fmt * fix clippy
1 parent 5bf2654 commit 10d3a22

File tree

5 files changed

+365
-8
lines changed

5 files changed

+365
-8
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cranelift/codegen/meta/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ cranelift-srcgen = { workspace = true }
2020
cranelift-assembler-x64-meta = { path = "../../assembler-x64/meta", version = "0.123.0" }
2121
cranelift-codegen-shared = { path = "../shared", version = "0.123.0" }
2222
pulley-interpreter = { workspace = true, optional = true }
23+
heck = "0.5.0"
2324

2425
[features]
2526
pulley = ['dep:pulley-interpreter']

cranelift/codegen/meta/src/gen_inst.rs

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use crate::cdsl::camel_case;
44
use crate::cdsl::formats::InstructionFormat;
55
use crate::cdsl::instructions::{AllInstructions, Instruction};
6-
use crate::cdsl::operands::Operand;
6+
use crate::cdsl::operands::{Operand, OperandKindFields};
77
use crate::cdsl::typevar::{TypeSet, TypeVar};
88
use crate::unique_table::{UniqueSeqTable, UniqueTable};
99
use cranelift_codegen_shared::constant_hash;
@@ -159,7 +159,7 @@ fn gen_arguments_method(formats: &[Rc<InstructionFormat>], fmt: &mut Formatter,
159159
/// - `pub fn eq(&self, &other: Self, &pool) -> bool`
160160
/// - `pub fn hash<H: Hasher>(&self, state: &mut H, &pool)`
161161
fn gen_instruction_data_impl(formats: &[Rc<InstructionFormat>], fmt: &mut Formatter) {
162-
fmt.add_block("impl InstructionData",|fmt| {
162+
fmt.add_block("impl InstructionData", |fmt| {
163163
fmt.doc_comment("Get the opcode of this instruction.");
164164
fmt.add_block("pub fn opcode(&self) -> Opcode",|fmt| {
165165
let mut m = Match::new("*self");
@@ -413,8 +413,98 @@ fn gen_instruction_data_impl(formats: &[Rc<InstructionFormat>], fmt: &mut Format
413413
});
414414
}
415415
});
416+
});
417+
fmt.doc_comment(r#"
418+
Map some functions, described by the given `InstructionMapper`, over each of the
419+
entities within this instruction, producing a new `InstructionData`.
420+
"#);
421+
fmt.add_block("pub fn map(&self, mut mapper: impl crate::ir::instructions::InstructionMapper) -> Self", |fmt| {
422+
fmt.add_block("match *self",|fmt| {
423+
for format in formats {
424+
let name = format!("Self::{}", format.name);
425+
let mut members = vec!["opcode"];
426+
427+
if format.has_value_list {
428+
members.push("args");
429+
} else if format.num_value_operands == 1 {
430+
members.push("arg");
431+
} else if format.num_value_operands > 0 {
432+
members.push("args");
433+
}
434+
435+
match format.num_block_operands {
436+
0 => {}
437+
1 => {
438+
members.push("destination");
439+
}
440+
_ => {
441+
members.push("blocks");
442+
}
443+
};
444+
445+
for field in &format.imm_fields {
446+
members.push(field.member);
447+
}
448+
let members = members.join(", ");
449+
450+
fmt.add_block(&format!("{name}{{{members}}} => "), |fmt| {
451+
fmt.add_block(&format!("Self::{}", format.name), |fmt| {
452+
fmtln!(fmt, "opcode,");
453+
454+
if format.has_value_list {
455+
fmtln!(fmt, "args: mapper.map_value_list(args),");
456+
} else if format.num_value_operands == 1 {
457+
fmtln!(fmt, "arg: mapper.map_value(arg),");
458+
} else if format.num_value_operands > 0 {
459+
let maps = (0..format.num_value_operands)
460+
.map(|i| format!("mapper.map_value(args[{i}])"))
461+
.collect::<Box<[_]>>()
462+
.join(", ");
463+
fmtln!(fmt, "args: [{maps}],");
464+
}
465+
466+
match format.num_block_operands {
467+
0 => {}
468+
1 => {
469+
fmtln!(fmt, "destination: mapper.map_block_call(destination),");
470+
}
471+
2 => {
472+
fmtln!(fmt, "blocks: [mapper.map_block_call(blocks[0]), mapper.map_block_call(blocks[1])],");
473+
}
474+
_ => panic!("Too many block targets in instruction"),
475+
}
476+
477+
for field in &format.imm_fields {
478+
let member = field.member;
479+
match &field.kind.fields {
480+
OperandKindFields::EntityRef => {
481+
let mut kind = heck::ToSnakeCase::to_snake_case(
482+
field
483+
.kind
484+
.rust_type
485+
.split("::")
486+
.last()
487+
.unwrap_or(field.kind.rust_type),
488+
);
489+
if kind == "block" {
490+
kind.push_str("_call");
491+
}
492+
fmtln!(fmt, "{member}: mapper.map_{kind}({member}),");
493+
}
494+
OperandKindFields::VariableArgs => {
495+
fmtln!(fmt, "{member}: mapper.map_value_list({member}),");
496+
}
497+
OperandKindFields::ImmValue |
498+
OperandKindFields::ImmEnum(_) |
499+
OperandKindFields::TypeVar(_) => fmtln!(fmt, "{member},"),
500+
}
501+
}
502+
});
416503
});
504+
}
417505
});
506+
});
507+
});
418508
}
419509

420510
fn gen_bool_accessor<T: Fn(&Instruction) -> bool>(

0 commit comments

Comments
 (0)