1 use clap::Parser;
2 use std::path::PathBuf;
3 
4 mod bugpoint;
5 mod cat;
6 mod compile;
7 mod disasm;
8 mod interpret;
9 mod print_cfg;
10 mod run;
11 mod utils;
12 
13 #[cfg(feature = "souper-harvest")]
14 mod souper_harvest;
15 
16 /// Cranelift code generator utility.
17 #[derive(Parser)]
18 enum Commands {
19     Test(TestOptions),
20     Run(run::Options),
21     Interpret(interpret::Options),
22     Cat(cat::Options),
23     PrintCfg(print_cfg::Options),
24     Compile(compile::Options),
25     Pass(PassOptions),
26     Bugpoint(bugpoint::Options),
27 
28     #[cfg(feature = "souper-harvest")]
29     SouperHarvest(souper_harvest::Options),
30     #[cfg(not(feature = "souper-harvest"))]
31     SouperHarvest(CompiledWithoutSupportOptions),
32 }
33 
34 /// Run Cranelift tests
35 #[derive(Parser)]
36 struct TestOptions {
37     /// Be more verbose
38     #[arg(short, long)]
39     verbose: bool,
40 
41     /// Print pass timing report for test
42     #[arg(short = 'T')]
43     time_passes: bool,
44 
45     /// Specify an input file to be used. Use '-' for stdin.
46     #[arg(required = true)]
47     files: Vec<PathBuf>,
48 }
49 
50 /// Run specified pass(es) on an input file.
51 #[derive(Parser)]
52 struct PassOptions {
53     /// Be more verbose
54     #[arg(short, long)]
55     verbose: bool,
56 
57     /// Print pass timing report for test
58     #[arg(short = 'T')]
59     time_passes: bool,
60 
61     /// Specify an input file to be used. Use '-' for stdin.
62     file: PathBuf,
63 
64     /// Specify the target architecture.
65     target: String,
66 
67     /// Specify pass(es) to be run on the input file
68     #[arg(required = true)]
69     passes: Vec<String>,
70 }
71 
72 /// (Compiled without support for this subcommand)
73 #[derive(Parser)]
74 struct CompiledWithoutSupportOptions {}
75 
main() -> anyhow::Result<()>76 fn main() -> anyhow::Result<()> {
77     env_logger::init();
78 
79     match Commands::parse() {
80         Commands::Cat(c) => cat::run(&c)?,
81         Commands::Run(r) => run::run(&r)?,
82         Commands::Interpret(i) => interpret::run(&i)?,
83         Commands::PrintCfg(p) => print_cfg::run(&p)?,
84         Commands::Compile(c) => compile::run(&c)?,
85         Commands::Bugpoint(b) => bugpoint::run(&b)?,
86 
87         #[cfg(feature = "souper-harvest")]
88         Commands::SouperHarvest(s) => souper_harvest::run(&s)?,
89         #[cfg(not(feature = "souper-harvest"))]
90         Commands::SouperHarvest(_) => anyhow::bail!(
91             "Error: clif-util was compiled without support for the `souper-harvest` \
92              subcommand",
93         ),
94 
95         Commands::Test(t) => {
96             cranelift_filetests::run(
97                 t.verbose,
98                 t.time_passes,
99                 &t.files
100                     .iter()
101                     .map(|f| f.display().to_string())
102                     .collect::<Vec<_>>(),
103             )?;
104         }
105         Commands::Pass(p) => {
106             cranelift_filetests::run_passes(
107                 p.verbose,
108                 p.time_passes,
109                 &p.passes,
110                 &p.target,
111                 &p.file.display().to_string(),
112             )?;
113         }
114     }
115 
116     Ok(())
117 }
118 
119 #[test]
verify_cli()120 fn verify_cli() {
121     use clap::CommandFactory;
122     Commands::command().debug_assert()
123 }
124