forked from llvm/llvm-project
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdriver.cpp
147 lines (124 loc) · 5.24 KB
/
driver.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//===-- driver.cpp - Flang Driver -----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This is the entry point to the flang driver; it is a thin wrapper
// for functionality in the Driver flang library.
//
//===----------------------------------------------------------------------===//
#include "clang/Driver/Driver.h"
#include "flang/Frontend/CompilerInvocation.h"
#include "flang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Driver/Compilation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/VirtualFileSystem.h"
using llvm::StringRef;
// main frontend method. Lives inside fc1_main.cpp
extern int fc1_main(llvm::ArrayRef<const char *> argv, const char *argv0);
std::string GetExecutablePath(const char *argv0) {
// This just needs to be some symbol in the binary
void *p = (void *)(intptr_t)GetExecutablePath;
return llvm::sys::fs::getMainExecutable(argv0, p);
}
// This lets us create the DiagnosticsEngine with a properly-filled-out
// DiagnosticOptions instance
static clang::DiagnosticOptions *CreateAndPopulateDiagOpts(
llvm::ArrayRef<const char *> argv) {
auto *diagOpts = new clang::DiagnosticOptions;
// Ignore missingArgCount and the return value of ParseDiagnosticArgs.
// Any errors that would be diagnosed here will also be diagnosed later,
// when the DiagnosticsEngine actually exists.
unsigned missingArgIndex, missingArgCount;
llvm::opt::InputArgList args = clang::driver::getDriverOptTable().ParseArgs(
argv.slice(1), missingArgIndex, missingArgCount,
/*FlagsToInclude=*/clang::driver::options::FlangOption);
(void)Fortran::frontend::ParseDiagnosticArgs(*diagOpts, args);
return diagOpts;
}
static int ExecuteFC1Tool(llvm::SmallVectorImpl<const char *> &argV) {
llvm::StringRef tool = argV[1];
if (tool == "-fc1")
return fc1_main(makeArrayRef(argV).slice(2), argV[0]);
// Reject unknown tools.
// ATM it only supports fc1. Any fc1[*] is rejected.
llvm::errs() << "error: unknown integrated tool '" << tool << "'. "
<< "Valid tools include '-fc1'.\n";
return 1;
}
int main(int argc, const char **argv) {
// Initialize variables to call the driver
llvm::InitLLVM x(argc, argv);
llvm::SmallVector<const char *, 256> args(argv, argv + argc);
clang::driver::ParsedClangName targetandMode("flang", "--driver-mode=flang");
std::string driverPath = GetExecutablePath(args[0]);
// Check if flang-new is in the frontend mode
auto firstArg = std::find_if(
args.begin() + 1, args.end(), [](const char *a) { return a != nullptr; });
if (firstArg != args.end()) {
if (llvm::StringRef(args[1]).startswith("-cc1")) {
llvm::errs() << "error: unknown integrated tool '" << args[1] << "'. "
<< "Valid tools include '-fc1'.\n";
return 1;
}
// Call flang-new frontend
if (llvm::StringRef(args[1]).startswith("-fc1")) {
return ExecuteFC1Tool(args);
}
}
// Not in the frontend mode - continue in the compiler driver mode.
// Create DiagnosticsEngine for the compiler driver
llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagOpts =
CreateAndPopulateDiagOpts(args);
llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID(
new clang::DiagnosticIDs());
Fortran::frontend::TextDiagnosticPrinter *diagClient =
new Fortran::frontend::TextDiagnosticPrinter(llvm::errs(), &*diagOpts);
diagClient->set_prefix(
std::string(llvm::sys::path::stem(GetExecutablePath(args[0]))));
clang::DiagnosticsEngine diags(diagID, &*diagOpts, diagClient);
// Prepare the driver
clang::driver::Driver theDriver(driverPath,
llvm::sys::getDefaultTargetTriple(), diags, "flang LLVM compiler");
theDriver.setTargetAndMode(targetandMode);
std::unique_ptr<clang::driver::Compilation> c(
theDriver.BuildCompilation(args));
llvm::SmallVector<std::pair<int, const clang::driver::Command *>, 4>
failingCommands;
// Run the driver
int res = 1;
bool isCrash = false;
res = theDriver.ExecuteCompilation(*c, failingCommands);
for (const auto &p : failingCommands) {
int CommandRes = p.first;
const clang::driver::Command *failingCommand = p.second;
if (!res)
res = CommandRes;
// If result status is < 0 (e.g. when sys::ExecuteAndWait returns -1),
// then the driver command signalled an error. On Windows, abort will
// return an exit code of 3. In these cases, generate additional diagnostic
// information if possible.
isCrash = CommandRes < 0;
#ifdef _WIN32
isCrash |= CommandRes == 3;
#endif
if (isCrash) {
theDriver.generateCompilationDiagnostics(*c, *failingCommand);
break;
}
}
diags.getClient()->finish();
// If we have multiple failing commands, we return the result of the first
// failing command.
return res;
}