blob: 631e9b71f31ae883c5edc9594aa30a24e664698d [file] [log] [blame]
Zonr Changc383a502010-10-12 01:52:08 +08001/*
Stephen Hines0a813a32012-08-03 16:52:40 -07002 * Copyright 2010-2012, The Android Open Source Project
Zonr Changc383a502010-10-12 01:52:08 +08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Stephen Hines8b5c5c62014-06-06 18:03:18 -070017#include "clang/Basic/DiagnosticOptions.h"
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070018#include "clang/Driver/DriverDiagnostic.h"
Stephen Hinesa1f95ee2013-08-09 01:26:08 -070019#include "clang/Driver/Options.h"
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -070020#include "clang/Frontend/CompilerInvocation.h"
21#include "clang/Frontend/FrontendDiagnostic.h"
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070022#include "clang/Frontend/TextDiagnosticPrinter.h"
Stephen Hines8f4d9722011-12-05 14:14:42 -080023#include "clang/Frontend/Utils.h"
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070024
Stephen Hinese639eb52010-11-08 19:27:20 -080025#include "llvm/ADT/SmallVector.h"
Loganbe274822011-02-16 22:02:54 +080026#include "llvm/ADT/IntrusiveRefCntPtr.h"
Stephen Hinese639eb52010-11-08 19:27:20 -080027
Stephen Hinesa1f95ee2013-08-09 01:26:08 -070028#include "llvm/Option/OptTable.h"
Pirama Arumuga Nainar1906a002015-06-29 10:30:41 -070029#include "llvm/Support/Allocator.h"
Stephen Hinese639eb52010-11-08 19:27:20 -080030#include "llvm/Support/ManagedStatic.h"
31#include "llvm/Support/MemoryBuffer.h"
Loganbe274822011-02-16 22:02:54 +080032#include "llvm/Support/Path.h"
Stephen Hinesba7c6dc2011-09-07 19:57:04 -070033#include "llvm/Support/raw_ostream.h"
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -070034#include "llvm/Support/Signals.h"
Pirama Arumuga Nainar1906a002015-06-29 10:30:41 -070035#include "llvm/Support/StringSaver.h"
mkopec1c460b372012-01-09 11:21:50 -050036#include "llvm/Target/TargetMachine.h"
Stephen Hinese639eb52010-11-08 19:27:20 -080037
Elliott Hughes9534de12015-07-29 14:07:37 -070038#include "os_sep.h"
Stephen Hines8b5c5c62014-06-06 18:03:18 -070039#include "rs_cc_options.h"
Stephen Hinese639eb52010-11-08 19:27:20 -080040#include "slang.h"
Stephen Hines6e6578a2011-02-07 18:05:48 -080041#include "slang_assert.h"
Stephen Hines8f4d9722011-12-05 14:14:42 -080042#include "slang_diagnostic_buffer.h"
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070043#include "slang_rs_reflect_utils.h"
44
Stephen Hines8b5c5c62014-06-06 18:03:18 -070045#include <list>
46#include <set>
47#include <string>
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070048
Jean-Luc Brouilletc2473632015-05-14 13:07:47 -070049namespace {
Pirama Arumuga Nainar1906a002015-06-29 10:30:41 -070050class StringSet : public llvm::StringSaver {
Jean-Luc Brouilletc2473632015-05-14 13:07:47 -070051public:
Pirama Arumuga Nainar1906a002015-06-29 10:30:41 -070052 const char *saveImpl(llvm::StringRef Str) override {
53 return Strings.insert(Str.str()).first->c_str();
Jean-Luc Brouilletc2473632015-05-14 13:07:47 -070054 }
55
Pirama Arumuga Nainar1906a002015-06-29 10:30:41 -070056 StringSet() : llvm::StringSaver(A), A() {}
57
Jean-Luc Brouilletc2473632015-05-14 13:07:47 -070058private:
59 std::set<std::string> Strings;
Pirama Arumuga Nainar1906a002015-06-29 10:30:41 -070060 llvm::BumpPtrAllocator A;
Jean-Luc Brouilletc2473632015-05-14 13:07:47 -070061};
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070062}
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070063
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070064static const char *DetermineOutputFile(const std::string &OutputDir,
Stephen Hines9ae18b22014-06-10 23:53:00 -070065 const std::string &PathSuffix,
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070066 const char *InputFile,
Stephen Hinese639eb52010-11-08 19:27:20 -080067 slang::Slang::OutputType OutputType,
Jean-Luc Brouilletc2473632015-05-14 13:07:47 -070068 StringSet *SavedStrings) {
Stephen Hinese639eb52010-11-08 19:27:20 -080069 if (OutputType == slang::Slang::OT_Nothing)
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070070 return "/dev/null";
71
72 std::string OutputFile(OutputDir);
73
Stephen Hines7f5704e2014-06-10 18:06:50 -070074 // Append '/' to Opts.mBitcodeOutputDir if not presents
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070075 if (!OutputFile.empty() &&
Raphael8d5a2f62011-02-08 00:15:05 -080076 (OutputFile[OutputFile.size() - 1]) != OS_PATH_SEPARATOR)
77 OutputFile.append(1, OS_PATH_SEPARATOR);
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070078
Stephen Hines9ae18b22014-06-10 23:53:00 -070079 if (!PathSuffix.empty()) {
80 OutputFile.append(PathSuffix);
81 OutputFile.append(1, OS_PATH_SEPARATOR);
82 }
83
Stephen Hinese639eb52010-11-08 19:27:20 -080084 if (OutputType == slang::Slang::OT_Dependency) {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070085 // The build system wants the .d file name stem to be exactly the same as
86 // the source .rs file, instead of the .bc file.
Stephen Hinese639eb52010-11-08 19:27:20 -080087 OutputFile.append(slang::RSSlangReflectUtils::GetFileNameStem(InputFile));
88 } else {
89 OutputFile.append(
90 slang::RSSlangReflectUtils::BCFileNameFromRSFileName(InputFile));
91 }
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070092
Stephen Hinese639eb52010-11-08 19:27:20 -080093 switch (OutputType) {
94 case slang::Slang::OT_Dependency: {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070095 OutputFile.append(".d");
96 break;
97 }
Stephen Hinese639eb52010-11-08 19:27:20 -080098 case slang::Slang::OT_Assembly: {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070099 OutputFile.append(".S");
100 break;
101 }
Stephen Hinese639eb52010-11-08 19:27:20 -0800102 case slang::Slang::OT_LLVMAssembly: {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700103 OutputFile.append(".ll");
104 break;
105 }
Stephen Hinese639eb52010-11-08 19:27:20 -0800106 case slang::Slang::OT_Object: {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700107 OutputFile.append(".o");
108 break;
109 }
Stephen Hinese639eb52010-11-08 19:27:20 -0800110 case slang::Slang::OT_Bitcode: {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700111 OutputFile.append(".bc");
112 break;
113 }
Stephen Hinese639eb52010-11-08 19:27:20 -0800114 case slang::Slang::OT_Nothing:
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700115 default: {
Stephen Hines6e6578a2011-02-07 18:05:48 -0800116 slangAssert(false && "Invalid output type!");
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700117 }
118 }
119
Pirama Arumuga Nainar1906a002015-06-29 10:30:41 -0700120 return SavedStrings->save(OutputFile.c_str());
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700121}
122
Stephen Hines9ae18b22014-06-10 23:53:00 -0700123typedef std::list<std::pair<const char*, const char*> > NamePairList;
124
125/*
126 * Compile the Inputs.
127 *
128 * Returns 0 on success and nonzero on failure.
129 *
130 * IOFiles - list of (foo.rs, foo.bc) pairs of input/output files.
131 * IOFiles32 - list of input/output pairs for 32-bit compilation.
132 * Inputs - input filenames.
133 * Opts - options controlling compilation.
134 * DiagEngine - Clang diagnostic engine (for creating diagnostics).
135 * DiagClient - Slang diagnostic consumer (collects and displays diagnostics).
136 * SavedStrings - expanded strings copied from argv source input files.
137 *
138 * We populate IOFiles dynamically while working through the list of Inputs.
139 * On any 64-bit compilation, we pass back in the 32-bit pairs of files as
140 * IOFiles32. This allows the 64-bit compiler to later bundle up both the
141 * 32-bit and 64-bit bitcode outputs to be included in the final reflected
142 * source code that is emitted.
143 */
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700144static void makeFileList(NamePairList *IOFiles, NamePairList *DepFiles,
Stephen Hines9ae18b22014-06-10 23:53:00 -0700145 const llvm::SmallVector<const char*, 16> &Inputs, slang::RSCCOptions &Opts,
Jean-Luc Brouilletc2473632015-05-14 13:07:47 -0700146 StringSet *SavedStrings) {
Stephen Hines9ae18b22014-06-10 23:53:00 -0700147 std::string PathSuffix = "";
Stephen Hines9ae18b22014-06-10 23:53:00 -0700148 // In our mixed 32/64-bit path, we need to suffix our files differently for
149 // both 32-bit and 64-bit versions.
150 if (Opts.mEmit3264) {
151 if (Opts.mBitWidth == 64) {
152 PathSuffix = "bc64";
153 } else {
154 PathSuffix = "bc32";
155 }
156 }
157
158 for (int i = 0, e = Inputs.size(); i != e; i++) {
159 const char *InputFile = Inputs[i];
160
161 const char *BCOutputFile = DetermineOutputFile(Opts.mBitcodeOutputDir,
162 PathSuffix, InputFile,
Yang Ni76837a12015-04-28 17:30:51 -0700163 Opts.mOutputType,
Jean-Luc Brouilletc2473632015-05-14 13:07:47 -0700164 SavedStrings);
Stephen Hines9ae18b22014-06-10 23:53:00 -0700165 const char *OutputFile = BCOutputFile;
166
167 if (Opts.mEmitDependency) {
168 // The dependency file is always emitted without a PathSuffix.
169 // Collisions between 32-bit and 64-bit files don't make a difference,
170 // because they share the same sources/dependencies.
171 const char *DepOutputFile =
172 DetermineOutputFile(Opts.mDependencyOutputDir, "", InputFile,
Jean-Luc Brouilletc2473632015-05-14 13:07:47 -0700173 slang::Slang::OT_Dependency, SavedStrings);
Stephen Hines9ae18b22014-06-10 23:53:00 -0700174 if (Opts.mOutputType == slang::Slang::OT_Dependency) {
175 OutputFile = DepOutputFile;
176 }
177
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700178 DepFiles->push_back(std::make_pair(BCOutputFile, DepOutputFile));
Stephen Hines9ae18b22014-06-10 23:53:00 -0700179 }
180
181 IOFiles->push_back(std::make_pair(InputFile, OutputFile));
182 }
Stephen Hines9ae18b22014-06-10 23:53:00 -0700183}
184
Stephen Hinesba7c6dc2011-09-07 19:57:04 -0700185#define str(s) #s
186#define wrap_str(s) str(s)
187static void llvm_rs_cc_VersionPrinter() {
188 llvm::raw_ostream &OS = llvm::outs();
189 OS << "llvm-rs-cc: Renderscript compiler\n"
190 << " (http://developer.android.com/guide/topics/renderscript)\n"
191 << " based on LLVM (http://llvm.org):\n";
192 OS << " Built " << __DATE__ << " (" << __TIME__ ").\n";
193 OS << " Target APIs: " << SLANG_MINIMUM_TARGET_API << " - "
194 << SLANG_MAXIMUM_TARGET_API;
195 OS << "\n Build type: " << wrap_str(TARGET_BUILD_VARIANT);
196#ifndef __DISABLE_ASSERTS
197 OS << " with assertions";
198#endif
199 OS << ".\n";
Stephen Hinesba7c6dc2011-09-07 19:57:04 -0700200}
Stephen Hines8f4d9722011-12-05 14:14:42 -0800201#undef wrap_str
202#undef str
Stephen Hinesba7c6dc2011-09-07 19:57:04 -0700203
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700204static void LLVMErrorHandler(void *UserData, const std::string &Message,
205 bool GenCrashDialog) {
206 clang::DiagnosticsEngine *DiagEngine =
207 static_cast<clang::DiagnosticsEngine *>(UserData);
208
209 DiagEngine->Report(clang::diag::err_fe_error_backend) << Message;
210
211 // Run the interrupt handlers to make sure any special cleanups get done, in
212 // particular that we remove files registered with RemoveFileOnSignal.
213 llvm::sys::RunInterruptHandlers();
214
215 exit(1);
216}
217
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700218int main(int argc, const char **argv) {
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700219 llvm::llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
220 LLVMInitializeARMTargetInfo();
221 LLVMInitializeARMTarget();
222 LLVMInitializeARMAsmPrinter();
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700223
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700224 StringSet SavedStrings; // Keeps track of strings to be destroyed at the end.
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700225
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700226 // Parse the command line arguments and respond to show help & version
227 // commands.
228 llvm::SmallVector<const char *, 16> Inputs;
Jean-Luc Brouilletc2473632015-05-14 13:07:47 -0700229 slang::RSCCOptions Opts;
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700230 llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts =
231 new clang::DiagnosticOptions();
232 if (!slang::ParseArguments(llvm::makeArrayRef(argv, argc), Inputs, Opts,
233 *DiagOpts, SavedStrings)) {
234 // Exits when there's any error occurred during parsing the arguments
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700235 return 1;
Stephen Hines8f4d9722011-12-05 14:14:42 -0800236 }
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700237 if (Opts.mShowHelp) {
Stephen Hines7ac9d0d2014-07-15 16:50:03 -0700238 std::unique_ptr<llvm::opt::OptTable> OptTbl(slang::createRSCCOptTable());
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700239 const std::string Argv0 = llvm::sys::path::stem(argv[0]);
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700240 OptTbl->PrintHelp(llvm::outs(), Argv0.c_str(),
Stephen Hinesb7d12692011-09-02 18:16:19 -0700241 "Renderscript source compiler");
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700242 return 0;
243 }
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700244 if (Opts.mShowVersion) {
Stephen Hinesba7c6dc2011-09-07 19:57:04 -0700245 llvm_rs_cc_VersionPrinter();
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700246 return 0;
247 }
248
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700249 // Initialize the diagnostic objects
250 llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs(
251 new clang::DiagnosticIDs());
252 slang::DiagnosticBuffer DiagsBuffer;
253 clang::DiagnosticsEngine DiagEngine(DiagIDs, &*DiagOpts, &DiagsBuffer, false);
254 clang::ProcessWarningOptions(DiagEngine, *DiagOpts);
255 (void)DiagEngine.setSeverityForGroup(clang::diag::Flavor::WarningOrError,
256 "implicit-function-declaration",
257 clang::diag::Severity::Error);
258
259 // Report error if no input file
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700260 if (Inputs.empty()) {
Logan Chien9207a2e2011-10-21 15:39:28 +0800261 DiagEngine.Report(clang::diag::err_drv_no_input_files);
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700262 llvm::errs() << DiagsBuffer.str();
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700263 return 1;
264 }
265
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700266 llvm::install_fatal_error_handler(LLVMErrorHandler, &DiagEngine);
Zonr Changcf6af6a2010-10-12 12:38:51 +0800267
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700268 // Compile the 32 bit version
269 NamePairList IOFiles32;
270 NamePairList DepFiles32;
271 makeFileList(&IOFiles32, &DepFiles32, Inputs, Opts, &SavedStrings);
272
Miao Wangbfbdd982015-06-25 15:04:35 -0700273 int CompileFailed = 0;
274 // Handle 32-bit case for Java and C++ reflection.
275 // For Java, both 32bit and 64bit will be generated.
276 // For C++, either 64bit or 32bit will be generated based on the target.
277 if (Opts.mEmit3264 || Opts.mBitWidth == 32) {
278 std::unique_ptr<slang::Slang> Compiler(
279 new slang::Slang(32, &DiagEngine, &DiagsBuffer));
280 CompileFailed =
281 !Compiler->compile(IOFiles32, IOFiles32, DepFiles32, Opts, *DiagOpts);
282 }
Zonr Chang641558f2010-10-12 21:07:06 +0800283
Stephen Hines9ae18b22014-06-10 23:53:00 -0700284 // Handle the 64-bit case too!
Miao Wangbfbdd982015-06-25 15:04:35 -0700285 bool needEmit64 = Opts.mEmit3264 || Opts.mBitWidth == 64;
286 if (needEmit64 && !CompileFailed) {
Stephen Hines9ae18b22014-06-10 23:53:00 -0700287 Opts.mBitWidth = 64;
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700288 NamePairList IOFiles64;
289 NamePairList DepFiles64;
290 makeFileList(&IOFiles64, &DepFiles64, Inputs, Opts, &SavedStrings);
291
292 std::unique_ptr<slang::Slang> Compiler(
293 new slang::Slang(64, &DiagEngine, &DiagsBuffer));
294 CompileFailed =
295 !Compiler->compile(IOFiles64, IOFiles32, DepFiles64, Opts, *DiagOpts);
Zonr Changcf6af6a2010-10-12 12:38:51 +0800296 }
297
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700298 llvm::errs() << DiagsBuffer.str();
299 llvm::remove_fatal_error_handler();
Stephen Hinesd7f0ea22011-02-22 17:45:19 -0800300 return CompileFailed;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700301}