1 #include "driver/driver.h"
2 #include "lexer/lexer.h"
3 #include "source_file/token.h"
4 #include "analysis/type_check.h"
5 #include "analysis/register_declarations.h"
6 #include "analysis/organize_packages.h"
7 #include "analysis/type_precheck.h"
8 #include "analysis/scan_imports.h"
9 #include "codegen/code_generator.h"
10 #include "include/ast/package.h"
11 #include "ast/intrinsic.h"
13 #include "ast/package.h"
14 #include "source_file/source_file.h"
15 #include "parser/parser.h"
16 #include "llvm_api/clang_frontend.h"
17 #include "linker/linker.h"
18 #include "llvm_api/llvm_ar.h"
21 #include "llvm/ADT/StringRef.h"
22 #include <llvm/Support/TargetSelect.h>
23 #include <llvm/MC/TargetRegistry.h>
24 #include <llvm/Target/TargetOptions.h>
25 #include <llvm/Support/FileSystem.h>
26 #include <llvm/IR/LegacyPassManager.h>
27 #include <llvm/Transforms/InstCombine/InstCombine.h>
28 #include <llvm/Transforms/IPO/PassManagerBuilder.h>
29 #include <llvm/Transforms/Scalar.h>
30 #include <llvm/Transforms/Scalar/GVN.h>
31 #include <llvm/Support/CodeGen.h>
32 #include <clang/Basic/TargetOptions.h>
33 #include <clang/Frontend/CompilerInvocation.h>
34 #include <llvm/LinkAllPasses.h>
35 #include <llvm/Option/OptTable.h>
36 #include <llvm/Support/ManagedStatic.h>
37 #include <llvm/Analysis/TargetTransformInfo.h>
38 #include <clang/Basic/Diagnostic.h>
39 #include <clang/Basic/DiagnosticOptions.h>
40 #include <llvm/MC/MCAsmBackend.h>
41 #include <llvm/MC/MCAsmInfo.h>
42 #include <llvm/MC/MCCodeEmitter.h>
43 #include <llvm/MC/MCContext.h>
44 #include <llvm/MC/MCInstrInfo.h>
45 #include <llvm/MC/MCObjectWriter.h>
46 #include <llvm/MC/MCParser/MCAsmParser.h>
47 #include <llvm/MC/MCParser/MCTargetAsmParser.h>
48 #include <llvm/MC/MCRegisterInfo.h>
49 #include <llvm/MC/MCSectionMachO.h>
50 #include <llvm/MC/MCStreamer.h>
51 #include <llvm/MC/MCSubtargetInfo.h>
52 #include <llvm/Support/Host.h>
53 #include <llvm/Support/MemoryBuffer.h>
54 #include <llvm/Support/SourceMgr.h>
55 #include <llvm/Support/Regex.h>
56 #include <llvm/Support/StringSaver.h>
57 #include <llvm/Object/Archive.h>
58 #include <llvm/Object/IRObjectFile.h>
59 #include <llvm/Support/ConvertUTF.h>
60 #include <llvm/Support/FormatVariadic.h>
61 #include <llvm/Support/LineIterator.h>
62 #include <lld/Common/Driver.h>
63 #include <llvm/Analysis/LoopAnalysisManager.h>
64 #include <llvm/Analysis/CGSCCPassManager.h>
65 #include <llvm/Passes/PassBuilder.h>
67 using namespace tanlang;
68 namespace fs = std::filesystem;
71 static constexpr std::array CXX_EXTS{
".cpp",
90 static constexpr str_view TAN_EXT =
".tan";
92 static umap<TanOptLevel, llvm::CodeGenOpt::Level> tan_to_llvm_opt_level{
93 {O0, llvm::CodeGenOpt::None },
94 {O1, llvm::CodeGenOpt::Less },
95 {O2, llvm::CodeGenOpt::Default },
96 {O3, llvm::CodeGenOpt::Aggressive},
99 void verify_dirs(
const vector<str> &dirs);
104 vector<str> compile_cxx(
const vector<str> &files,
TanCompilation config);
106 static str search_library(
const vector<str> &lib_dirs,
const str &lib_name);
108 CompilerDriver::~CompilerDriver() { singleton =
nullptr; }
123 llvm::InitializeAllTargetInfos();
124 llvm::InitializeAllTargets();
125 llvm::InitializeAllTargetMCs();
126 llvm::InitializeAllAsmParsers();
127 llvm::InitializeAllAsmPrinters();
128 auto target_triple = llvm::sys::getDefaultTargetTriple();
130 auto target = llvm::TargetRegistry::lookupTarget(target_triple, error);
136 auto CPU =
"generic";
138 llvm::TargetOptions opt;
140 auto RM = llvm::Reloc::Model::PIC_;
141 _target_machine = target->createTargetMachine(target_triple, CPU, features, opt, RM);
149 vector<str> tan_files{};
150 vector<str> cxx_files{};
151 for (
size_t i = 0; i < files.size(); ++i) {
152 fs::path f = fs::path(files[i]);
153 str ext = f.extension().string();
156 Error(ErrorType::FILE_NOT_FOUND, fmt::format(
"File not found: {}", files[i])).raise();
158 bool is_cxx = std::any_of(CXX_EXTS.begin(), CXX_EXTS.end(), [=](
const str &e) { return e == ext; });
160 cxx_files.push_back(files[i]);
161 }
else if (ext == TAN_EXT) {
162 tan_files.push_back(files[i]);
164 Error(ErrorType::GENERIC_ERROR, fmt::format(
"Unrecognized source file: {}", files[i])).raise();
169 auto cxx_objs = compile_cxx(cxx_files, _config);
170 auto tan_objs = compile_tan(tan_files);
173 vector<str> obj_files(cxx_objs.size() + tan_objs.size());
175 for (
const str &o : cxx_objs)
177 for (
const str &o : tan_objs)
184 auto q = _packages.find(name);
185 if (q != _packages.end()) {
194 TAN_ASSERT(!programs.empty());
197 for (
auto *p : programs) {
204 vector<Package *> ps = op.run(programs);
207 vector<Package *> packages{};
209 AnalyzeStatus status = _package_status[p->get_name()];
210 if (status == AnalyzeStatus::None) {
211 packages.push_back(p);
212 }
else if (status == AnalyzeStatus::Processing) {
214 Error(ErrorType::IMPORT_ERROR,
"Cyclic package dependency detected for package: " + p->get_name()).raise();
220 for (
auto *p : packages) {
225 for (
auto *p : packages) {
226 _package_status[p->get_name()] = AnalyzeStatus::Processing;
228 uset<str> import_files{};
229 uset<str> import_names{};
232 auto res = si.run(p);
233 for (
const auto &e : res) {
234 import_names.insert(e.first);
235 import_files.insert(e.second.begin(), e.second.end());
239 if (!import_files.empty()) {
240 vector<Package *> import_packages =
stage1_analysis(
parse(vector<str>(import_files.begin(), import_files.end())));
241 for (
Package *ip : import_packages) {
242 if (import_names.contains(ip->get_name())) {
248 _package_status[p->get_name()] = AnalyzeStatus::Done;
252 for (
auto *p : packages) {
260 vector<str> CompilerDriver::compile_tan(
const vector<str> &files) {
261 bool print_ir_code = _config.
verbose >= 1;
262 size_t n_files = files.size();
263 vector<str> ret(n_files);
266 auto programs =
parse(files);
270 for (
auto *p : programs) {
271 std::cout << fmt::format(
"AST Tree of {}:\n{}", p->src()->get_filename(), p->repr());
280 for (
auto [name, p] : _packages) {
287 for (
auto *p : packages) {
288 std::cout << fmt::format(
"Compiling TAN package: {}\n", p->get_name());
291 _target_machine->setOptLevel(tan_to_llvm_opt_level[_config.
opt_level]);
299 str ofile = ret[i] = fs::path(p->get_name() +
".o").filename().string();
300 cg->emit_to_file(ofile);
307 for (
auto *p : programs) {
314 TAN_ASSERT(!files.empty());
316 vector<Program *> ret{};
318 for (
const str &file : files) {
323 auto tokens = tokenize(source);
326 auto *parser =
new Parser(sm);
327 auto *ast = parser->parse();
332 for (
auto *f : intrinsic_funcs) {
333 ast->ctx()->set_function_decl(f);
343 auto import_path = fs::path(import_name);
346 if (import_path.is_absolute() && fs::exists(import_path)) {
347 return {import_path.string()};
354 auto p = fs::path(callee_path).parent_path() / import_path;
355 p = p.lexically_normal();
356 if (fs::exists(p) || fs::exists(p.replace_extension(
".tan"))) {
357 ret.push_back(fs::absolute(p).
string());
363 auto p = fs::path(rel) / import_path;
364 p = p.lexically_normal();
365 if (fs::exists(p) || fs::exists(p.replace_extension(
".tan"))) {
366 ret.push_back(fs::absolute(p).
string());
374 void CompilerDriver::link(
const std::vector<str> &files) {
375 if (_config.type == SLIB) {
377 vector<str> all_files(files.begin(), files.end());
379 str path = search_library(_config.
lib_dirs, lib);
382 Error(ErrorType::LINK_ERROR, fmt::format(
"Unable to find library: {}", lib)).raise();
384 all_files.push_back(path);
387 llvm_ar_create_static_lib(_config.
out_file, all_files);
394 linker.add_files(files);
395 linker.add_flag(
"-o" + str(_config.
out_file));
396 if (_config.type == EXE) {
397 linker.add_flags({
"-fPIE"});
398 }
else if (_config.type == DLIB) {
399 linker.add_flags({
"-shared"});
403 size_t n_lib_dirs = _config.
lib_dirs.size();
404 for (
size_t i = 0; i < n_lib_dirs; ++i) {
405 auto p = fs::absolute(fs::path(_config.
lib_dirs[i]));
406 linker.add_flag(
"-L" + p.string());
407 linker.add_flag(
"-Wl,-rpath," + p.string());
411 size_t n_link_files = _config.
link_files.size();
412 for (
size_t i = 0; i < n_link_files; ++i) {
413 linker.add_flag(
"-l" + std::string(_config.
link_files[i]));
415 linker.add_flag(opt_level_to_string(_config.
opt_level));
418 Error(ErrorType::LINK_ERROR,
"Failed linking").raise();
425 vector<str> compile_cxx(
const vector<str> &files,
TanCompilation config) {
426 vector<str> obj_files{};
428 if (!files.empty()) {
429 std::cout <<
"Compiling " << files.size() <<
" CXX file(s): ";
430 std::for_each(files.begin(), files.end(), [=](
auto f) { std::cout << f <<
" "; });
433 auto err_code = clang_compile(files, &config);
435 Error(ErrorType::GENERIC_ERROR,
"Failed to compile CXX files").raise();
438 size_t n = files.size();
439 obj_files.reserve(n);
440 for (
size_t i = 0; i < n; ++i) {
441 auto p = fs::path(str(files[i])).replace_extension(
".o").filename();
442 obj_files.push_back(p.string());
449 void verify_dirs(
const vector<str> &dirs) {
450 for (
size_t i = 0; i < dirs.size(); ++i) {
451 fs::path p = fs::path(dirs[i]);
454 Error(ErrorType::FILE_NOT_FOUND, fmt::format(
"File not found: {}", dirs[i])).raise();
456 if (!fs::is_directory(p))
457 Error(ErrorType::FILE_NOT_FOUND, fmt::format(
"Not a directory: {}", dirs[i])).raise();
461 str search_library(
const std::vector<str> &lib_dirs,
const str &lib_name) {
463 for (
const str &dir : lib_dirs) {
464 vector<fs::path> candidates = {
466 fs::path(dir) / fs::path(lib_name),
467 fs::path(dir) / fs::path(lib_name +
".a"),
468 fs::path(dir) / fs::path(lib_name +
".so"),
469 fs::path(dir) / fs::path(
"lib" + lib_name +
".a"),
470 fs::path(dir) / fs::path(
"lib" + lib_name +
".so"),
473 for (
const auto &p : candidates) {
vector< Package * > stage1_analysis(vector< Program * > ps)
Get a set of partially analyzed packages that can be used for cross-package dependency analysis....
Package * get_package(const str &name)
Get a pointer to a Package. Semantic analysis is not guaranteed to be fully performed on it.
static vector< str > import_dirs
Import search directories FIXME: static variable?
void run(const vector< str > &files)
Compile CXX or TAN source files and link their output object files.
vector< Program * > parse(const vector< str > &files)
Parse the corresponding source file, and build AST.
static vector< str > resolve_package_import(const str &callee_path, const str &import_name)
Get a list of possible files that corresponds to an import. Check PACKAGES.md.
void register_package(const str &name, Package *package)
Register a Package that has been spotted from source files, with top-level context stored inside.
static vector< FunctionDecl * > GetIntrinsicFunctionDeclarations()
Generate a list of intrinsics function prototypes/declarations, such as @abort
Organize a list of source files into their corresponding packages according to the code....
Top Down Operator Precedence Parsing.
Register all declarations (including local) in the corresponding scopes. Run this stage early to easi...
Scans all dependencies in a package, and return their names and paths to relevant source files.
Different from SourceFile, TokenizedSourceFile manages the tokenized text of a source file.
Perform preliminary type checking. We try our best to resolve types, and remember those that cannot b...
Compilation configuration.
vector< str > import_dirs
Library search paths.
unsigned verbose
Optimization level,.
str out_file
Verbose level, 0 non-verbose, 1 print LLVM IR, 2, print LLVM IR and abstract syntax tree.
vector< str > link_files
Output filename, invalid if TanCompilation::type is set to OBJ.
TanOptLevel opt_level
Type of compilation,.
vector< str > lib_dirs
Files to link against.