1 //! This crate generates Rust sources for use by
2 //! [`cranelift_codegen`](../cranelift_codegen/index.html).
3 
4 use cranelift_srcgen::{Formatter, Language, error};
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").
isa_from_arch(arch: &str) -> Result<isa::Isa, String>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.
generate_rust(isas: &[isa::Isa], out_dir: &std::path::Path) -> Result<(), error::Error>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 
generate_rust_for_shared_defs( shared_defs: &Definitions, isas: &[isa::Isa], out_dir: &std::path::Path, ) -> Result<(), error::Error>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.
generate_isle(isle_dir: &std::path::Path) -> Result<(), error::Error>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 
generate_isle_for_shared_defs( shared_defs: &Definitions, isle_dir: &std::path::Path, ) -> Result<(), error::Error>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         "numerics.isle",
91         "isle_numerics.rs",
92         "clif_opt.isle",
93         "clif_lower.isle",
94         isle_dir,
95     )?;
96 
97     #[cfg(feature = "pulley")]
98     pulley::generate_isle("pulley_gen.isle", isle_dir)?;
99 
100     Ok(())
101 }
102 
103 /// Generate the ISLE definitions; this provides ISLE glue to access the
104 /// assembler instructions in [cranelift_assembler_x64_meta].
generate_isle_for_assembler( insts: &[cranelift_assembler_x64_meta::dsl::Inst], isle_dir: &std::path::Path, ) -> Result<(), error::Error>105 fn generate_isle_for_assembler(
106     insts: &[cranelift_assembler_x64_meta::dsl::Inst],
107     isle_dir: &std::path::Path,
108 ) -> Result<(), error::Error> {
109     let mut fmt = Formatter::new(Language::Isle);
110     gen_asm::generate_isle(&mut fmt, insts);
111     fmt.write("assembler.isle", isle_dir)
112 }
113 
114 /// Generate a macro containing builder functions for the assembler's ISLE
115 /// constructors; this provides Rust implementations backing up the ISLE
116 /// definitions in [generate_isle_for_assembler].
generate_rust_macro_for_assembler( insts: &[cranelift_assembler_x64_meta::dsl::Inst], out_dir: &std::path::Path, ) -> Result<(), error::Error>117 fn generate_rust_macro_for_assembler(
118     insts: &[cranelift_assembler_x64_meta::dsl::Inst],
119     out_dir: &std::path::Path,
120 ) -> Result<(), error::Error> {
121     let mut fmt = Formatter::new(Language::Rust);
122     gen_asm::generate_rust_macro(&mut fmt, insts);
123     fmt.write("assembler-isle-macro.rs", out_dir)
124 }
125 
126 /// Generates all the source files used in Cranelift from the meta-language.
generate( isas: &[isa::Isa], out_dir: &std::path::Path, isle_dir: &std::path::Path, ) -> Result<(), error::Error>127 pub fn generate(
128     isas: &[isa::Isa],
129     out_dir: &std::path::Path,
130     isle_dir: &std::path::Path,
131 ) -> Result<(), error::Error> {
132     let shared_defs = shared::define();
133     generate_rust_for_shared_defs(&shared_defs, isas, out_dir)?;
134     generate_isle_for_shared_defs(&shared_defs, isle_dir)?;
135 
136     let insts = cranelift_assembler_x64_meta::instructions::list();
137     generate_isle_for_assembler(&insts, isle_dir)?;
138     generate_rust_macro_for_assembler(&insts, out_dir)?;
139 
140     Ok(())
141 }
142