1 //! This crate generates Rust sources for use by
2 //! [`cranelift_codegen`](../cranelift_codegen/index.html).
3 
4 use cranelift_srcgen::{error, Formatter, Language};
5 use shared::Definitions;
6 
7 #[macro_use]
8 mod cdsl;
9 
10 pub mod isa;
11 pub mod isle;
12 
13 mod gen_asm;
14 mod gen_inst;
15 mod gen_isle;
16 mod gen_settings;
17 mod gen_types;
18 
19 mod constant_hash;
20 mod shared;
21 mod unique_table;
22 
23 #[cfg(feature = "pulley")]
24 mod pulley;
25 
26 /// Generate an ISA from an architecture string (e.g. "x86_64").
27 pub fn isa_from_arch(arch: &str) -> Result<isa::Isa, String> {
28     isa::Isa::from_arch(arch).ok_or_else(|| format!("no supported isa found for arch `{arch}`"))
29 }
30 
31 /// Generates all the Rust source files used in Cranelift from the meta-language.
32 pub fn generate_rust(isas: &[isa::Isa], out_dir: &std::path::Path) -> Result<(), error::Error> {
33     let shared_defs = shared::define();
34     generate_rust_for_shared_defs(&shared_defs, isas, out_dir)
35 }
36 
37 fn generate_rust_for_shared_defs(
38     shared_defs: &Definitions,
39     isas: &[isa::Isa],
40     out_dir: &std::path::Path,
41 ) -> Result<(), error::Error> {
42     gen_settings::generate(
43         &shared_defs.settings,
44         gen_settings::ParentGroup::None,
45         "settings.rs",
46         out_dir,
47     )?;
48 
49     gen_types::generate("types.rs", out_dir)?;
50 
51     gen_inst::generate(
52         &shared_defs.all_formats,
53         &shared_defs.all_instructions,
54         "opcodes.rs",
55         "inst_builder.rs",
56         out_dir,
57     )?;
58 
59     // Per ISA definitions.
60     for isa in isa::define(isas) {
61         gen_settings::generate(
62             &isa.settings,
63             gen_settings::ParentGroup::Shared,
64             &format!("settings-{}.rs", isa.name),
65             out_dir,
66         )?;
67     }
68 
69     #[cfg(feature = "pulley")]
70     if isas.contains(&isa::Isa::Pulley32) || isas.contains(&isa::Isa::Pulley64) {
71         pulley::generate_rust("pulley_inst_gen.rs", out_dir)?;
72     }
73 
74     Ok(())
75 }
76 
77 /// Generates all the ISLE source files used in Cranelift from the meta-language.
78 pub fn generate_isle(isle_dir: &std::path::Path) -> Result<(), error::Error> {
79     let shared_defs = shared::define();
80     generate_isle_for_shared_defs(&shared_defs, isle_dir)
81 }
82 
83 fn generate_isle_for_shared_defs(
84     shared_defs: &Definitions,
85     isle_dir: &std::path::Path,
86 ) -> Result<(), error::Error> {
87     gen_isle::generate(
88         &shared_defs.all_formats,
89         &shared_defs.all_instructions,
90         "clif_opt.isle",
91         "clif_lower.isle",
92         isle_dir,
93     )?;
94 
95     #[cfg(feature = "pulley")]
96     pulley::generate_isle("pulley_gen.isle", isle_dir)?;
97 
98     Ok(())
99 }
100 
101 /// Generate the ISLE definitions; this provides ISLE glue to access the
102 /// assembler instructions in [cranelift_assembler_x64_meta].
103 fn generate_isle_for_assembler(
104     insts: &[cranelift_assembler_x64_meta::dsl::Inst],
105     isle_dir: &std::path::Path,
106 ) -> Result<(), error::Error> {
107     let mut fmt = Formatter::new(Language::Isle);
108     gen_asm::generate_isle(&mut fmt, insts);
109     fmt.write("assembler.isle", isle_dir)
110 }
111 
112 /// Generate a macro containing builder functions for the assembler's ISLE
113 /// constructors; this provides Rust implementations backing up the ISLE
114 /// definitions in [generate_isle_for_assembler].
115 fn generate_rust_macro_for_assembler(
116     insts: &[cranelift_assembler_x64_meta::dsl::Inst],
117     out_dir: &std::path::Path,
118 ) -> Result<(), error::Error> {
119     let mut fmt = Formatter::new(Language::Rust);
120     gen_asm::generate_rust_macro(&mut fmt, insts);
121     fmt.write("assembler-isle-macro.rs", out_dir)
122 }
123 
124 /// Generates all the source files used in Cranelift from the meta-language.
125 pub fn generate(
126     isas: &[isa::Isa],
127     out_dir: &std::path::Path,
128     isle_dir: &std::path::Path,
129 ) -> Result<(), error::Error> {
130     let shared_defs = shared::define();
131     generate_rust_for_shared_defs(&shared_defs, isas, out_dir)?;
132     generate_isle_for_shared_defs(&shared_defs, isle_dir)?;
133 
134     let insts = cranelift_assembler_x64_meta::instructions::list();
135     generate_isle_for_assembler(&insts, isle_dir)?;
136     generate_rust_macro_for_assembler(&insts, out_dir)?;
137 
138     Ok(())
139 }
140