Thorin 1.9.0
The Higher ORder INtermediate representation
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1#include <cstdlib>
2#include <cstring>
3
4#include <fstream>
5#include <iostream>
6#include <lyra/lyra.hpp>
7
8#include "thorin/config.h"
9#include "thorin/driver.h"
10
11#include "thorin/be/dot/dot.h"
13#include "thorin/fe/parser.h"
15#include "thorin/pass/pass.h"
17#include "thorin/phase/phase.h"
18#include "thorin/util/sys.h"
19
20using namespace thorin;
21using namespace std::literals;
22
24
25int main(int argc, char** argv) {
26 try {
27 static const auto version = "thorin command-line utility version " THORIN_VER "\n";
28
29 Driver driver;
30 bool show_help = false;
31 bool show_version = false;
32 bool list_search_paths = false;
33 std::string input, prefix;
34 std::string clang = sys::find_cmd("clang");
35 std::vector<std::string> plugins, search_paths;
36#ifdef THORIN_ENABLE_CHECKS
37 std::vector<size_t> breakpoints;
38#endif
39 std::array<std::string, Num_Backends> output;
40 int verbose = 0;
41 int opt = 2;
42 auto inc_verbose = [&](bool) { ++verbose; };
43 auto& flags = driver.flags();
44
45 // clang-format off
46 auto cli = lyra::cli()
47 | lyra::help(show_help)
48 | lyra::opt(show_version )["-v"]["--version" ]("Display version info and exit.")
49 | lyra::opt(list_search_paths )["-l"]["--list-search-paths" ]("List search paths in order and exit.")
50 | lyra::opt(clang, "clang" )["-c"]["--clang" ]("Path to clang executable (default: '" THORIN_WHICH " clang').")
51 | lyra::opt(plugins, "plugin" )["-p"]["--plugin" ]("Dynamically load plugin.")
52 | lyra::opt(search_paths, "path" )["-P"]["--plugin-path" ]("Path to search for plugins.")
53 | lyra::opt(inc_verbose )["-V"]["--verbose" ]("Verbose mode. Multiple -V options increase the verbosity. The maximum is 4.").cardinality(0, 4)
54 | lyra::opt(opt, "level" )["-O"]["--optimize" ]("Optimization level (default: 2).")
55 | lyra::opt(output[Dot ], "file" ) ["--output-dot" ]("Emits the Thorin program as a graph using Graphviz' DOT language.")
56 | lyra::opt(output[H ], "file" ) ["--output-h" ]("Emits a header file to be used to interface with a plugin in C++.")
57 | lyra::opt(output[LL ], "file" ) ["--output-ll" ]("Compiles the Thorin program to LLVM.")
58 | lyra::opt(output[Md ], "file" ) ["--output-md" ]("Emits the input formatted as Markdown.")
59 | lyra::opt(output[Thorin], "file" )["-o"]["--output-thorin" ]("Emits the Thorin program again.")
60 | lyra::opt(flags.bootstrap ) ["--bootstrap" ]("Puts thorin into \"bootstrap mode\". This means a '.plugin' directive has the same effect as an '.import' and will not load a library. In addition, no standard plugins will be loaded.")
61 | lyra::opt(flags.dump_gid, "level" ) ["--dump-gid" ]("Dumps gid of inline expressions as a comment in output if <level> > 0. Use a <level> of 2 to also emit the gid of trivial defs.")
62 | lyra::opt(flags.dump_recursive ) ["--dump-recursive" ]("Dumps Thorin program with a simple recursive algorithm that is not readable again from Thorin but is less fragile and also works for broken Thorin programs.")
63 | lyra::opt(flags.aggressive_lam_spec ) ["--aggr-lam-spec" ]("Overrides LamSpec behavior to follow recursive calls.")
64 | lyra::opt(flags.scalerize_threshold, "threshold") ["--scalerize-threshold" ]("Thorin will not scalerize tuples/packs/sigmas/arrays with a number of elements greater than or equal this threshold.")
66 | lyra::opt(breakpoints, "gid" )["-b"]["--break" ]("*Triggers breakpoint upon construction of node with global id <gid>. Useful when running in a debugger.")
67 | lyra::opt(flags.reeval_breakpoints ) ["--reeval-breakpoints" ]("*Triggers breakpoint even upon unfying a node that has already been built.")
68 | lyra::opt(flags.break_on_alpha_unequal ) ["--break-on-alpha-unequal"]("*Triggers breakpoint as soon as two expressions turn out to be not alpha-equivalent.")
69 | lyra::opt(flags.break_on_error ) ["--break-on-error" ]("*Triggers breakpoint on ELOG.")
70 | lyra::opt(flags.break_on_warn ) ["--break-on-warn" ]("*Triggers breakpoint on WLOG.")
71 | lyra::opt(flags.trace_gids ) ["--trace-gids" ]("*Output gids during World::unify/insert.")
72#endif
73 | lyra::arg(input, "file" ) ("Input file.")
74 ;
75 // clang-format on
76
77 if (auto result = cli.parse({argc, argv}); !result) throw std::invalid_argument(result.message());
78
79 if (show_help) {
80 std::cout << cli << std::endl;
81#ifdef THORIN_ENABLE_CHECKS
82 std::cout << "*These are developer options only enabled, if 'THORIN_ENABLE_CHECKS' is ON." << std::endl;
83#endif
84 std::cout << "Use \"-\" as <file> to output to stdout." << std::endl;
85 return EXIT_SUCCESS;
86 }
87
88 if (show_version) {
89 std::cerr << version;
90 std::exit(EXIT_SUCCESS);
91 }
92
93 for (auto&& path : search_paths) driver.add_search_path(path);
94
95 if (list_search_paths) {
96 for (auto&& path : driver.search_paths() | std::views::drop(1)) // skip first empty path
97 std::cout << path << std::endl;
98 std::exit(EXIT_SUCCESS);
99 }
100
101 World& world = driver.world();
102#ifdef THORIN_ENABLE_CHECKS
103 for (auto b : breakpoints) world.breakpoint(b);
104#endif
105 driver.log().set(&std::cerr).set((Log::Level)verbose);
106
107 // prepare output files and streams
108 std::array<std::ofstream, Num_Backends> ofs;
109 std::array<std::ostream*, Num_Backends> os;
110 os.fill(nullptr);
111 for (size_t be = 0; be != Num_Backends; ++be) {
112 if (output[be].empty()) continue;
113 if (output[be] == "-") {
114 os[be] = &std::cout;
115 } else {
116 ofs[be].open(output[be]);
117 os[be] = &ofs[be];
118 }
119 }
120
121 // we always need standard plugins, as long as we are not in bootstrap mode
122 if (!flags.bootstrap) plugins.insert(plugins.end(), {"core", "mem", "compile", "opt"});
123
124 if (!plugins.empty())
125 for (const auto& plugin : plugins) driver.load(plugin);
126
127 if (input.empty()) throw std::invalid_argument("error: no input given");
128 if (input[0] == '-' || input.substr(0, 2) == "--")
129 throw std::invalid_argument("error: unknown option " + input);
130
131 auto path = fs::path(input);
132 world.set(path.filename().replace_extension().string());
133 auto parser = fe::Parser(world);
134 parser.import(input, os[Md]);
135
136 if (flags.bootstrap) {
137 if (auto h = os[H])
138 bootstrap(driver, world.sym(fs::path{path}.filename().replace_extension().string()), *h);
139 opt = std::min(opt, 1);
140 }
141
142 switch (opt) {
143 case 0: break;
144 case 1: Phase::run<Cleanup>(world); break;
145 case 2:
146 parser.import("opt");
147 optimize(world);
148 break;
149 default: error("illegal optimization level '{}'", opt);
150 }
151
152 if (os[Thorin]) world.dump(*os[Thorin]);
153 if (os[Dot]) dot::emit(world, *os[Dot]);
154
155 if (os[LL]) {
156 if (auto backend = driver.backend("ll"))
157 backend(world, *os[LL]);
158 else
159 error("'ll' emitter not loaded; try loading 'mem' plugin");
160 }
161 } catch (const std::exception& e) {
162 errln("{}", e.what());
163 return EXIT_FAILURE;
164 } catch (...) {
165 errln("error: unknown exception");
166 return EXIT_FAILURE;
167 }
168
169 return EXIT_SUCCESS;
170}
Some "global" variables needed all over the place.
Definition: driver.h:17
Flags & flags()
Definition: driver.h:23
The World represents the whole program and manages creation of Thorin nodes (Defs).
Definition: world.h:34
void set(Sym name)
Definition: world.h:88
Sym sym(std::string_view)
Definition: world.cpp:88
void dump(std::ostream &os)
Dump to os.
Definition: dump.cpp:377
void breakpoint(u32 gid)
Trigger breakpoint in your debugger when creating Def with Def::gid gid.
Definition: world.cpp:556
Parses Thorin code into the provided World.
Definition: parser.h:29
#define THORIN_VER
Definition: config.h:5
#define THORIN_ENABLE_CHECKS
Definition: config.h:3
Backends
Definition: main.cpp:23
@ LL
Definition: main.cpp:23
@ H
Definition: main.cpp:23
@ Thorin
Definition: main.cpp:23
@ Md
Definition: main.cpp:23
@ Num_Backends
Definition: main.cpp:23
@ Dot
Definition: main.cpp:23
int main(int argc, char **argv)
Definition: main.cpp:25
void emit(World &w, std::ostream &s, std::function< void(std::ostream &, const Def *)> stream_def)
Definition: dot.cpp:62
std::string find_cmd(std::string cmd)
Definition: sys.cpp:64
Definition: affine.h:7
std::ostream & errln(const char *fmt, Args &&... args)
Definition: print.h:179
void error(const Def *def, const char *fmt, Args &&... args)
Definition: def.h:544
void bootstrap(Driver &driver, Sym plugin, std::ostream &h)
Definition: bootstrap.cpp:11
void optimize(World &world)
Definition: optimize.cpp:19
#define THORIN_WHICH
Definition: sys.h:10