blob: 6b879e0b6e6d69cc846135198f1c43f4e4e4a390 [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"
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070020#include "clang/Frontend/TextDiagnosticPrinter.h"
Stephen Hines8f4d9722011-12-05 14:14:42 -080021#include "clang/Frontend/Utils.h"
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070022
Stephen Hinese639eb52010-11-08 19:27:20 -080023#include "llvm/ADT/SmallVector.h"
Loganbe274822011-02-16 22:02:54 +080024#include "llvm/ADT/IntrusiveRefCntPtr.h"
Stephen Hinese639eb52010-11-08 19:27:20 -080025
Stephen Hinesa1f95ee2013-08-09 01:26:08 -070026#include "llvm/Option/OptTable.h"
Stephen Hinese639eb52010-11-08 19:27:20 -080027#include "llvm/Support/CommandLine.h"
28#include "llvm/Support/ManagedStatic.h"
29#include "llvm/Support/MemoryBuffer.h"
Loganbe274822011-02-16 22:02:54 +080030#include "llvm/Support/Path.h"
Stephen Hinesba7c6dc2011-09-07 19:57:04 -070031#include "llvm/Support/raw_ostream.h"
mkopec1c460b372012-01-09 11:21:50 -050032#include "llvm/Target/TargetMachine.h"
Stephen Hinese639eb52010-11-08 19:27:20 -080033
Stephen Hines8b5c5c62014-06-06 18:03:18 -070034#include "rs_cc_options.h"
Stephen Hinese639eb52010-11-08 19:27:20 -080035#include "slang.h"
Stephen Hines6e6578a2011-02-07 18:05:48 -080036#include "slang_assert.h"
Stephen Hines8f4d9722011-12-05 14:14:42 -080037#include "slang_diagnostic_buffer.h"
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070038#include "slang_rs_reflect_utils.h"
39
Stephen Hines8b5c5c62014-06-06 18:03:18 -070040#include <list>
41#include <set>
42#include <string>
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070043
44// SaveStringInSet, ExpandArgsFromBuf and ExpandArgv are all copied from
45// $(CLANG_ROOT)/tools/driver/driver.cpp for processing argc/argv passed in
46// main().
47static inline const char *SaveStringInSet(std::set<std::string> &SavedStrings,
48 llvm::StringRef S) {
49 return SavedStrings.insert(S).first->c_str();
50}
51static void ExpandArgsFromBuf(const char *Arg,
52 llvm::SmallVectorImpl<const char*> &ArgVector,
53 std::set<std::string> &SavedStrings);
54static void ExpandArgv(int argc, const char **argv,
55 llvm::SmallVectorImpl<const char*> &ArgVector,
56 std::set<std::string> &SavedStrings);
57
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070058static const char *DetermineOutputFile(const std::string &OutputDir,
Stephen Hines9ae18b22014-06-10 23:53:00 -070059 const std::string &PathSuffix,
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070060 const char *InputFile,
Stephen Hinese639eb52010-11-08 19:27:20 -080061 slang::Slang::OutputType OutputType,
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070062 std::set<std::string> &SavedStrings) {
Stephen Hinese639eb52010-11-08 19:27:20 -080063 if (OutputType == slang::Slang::OT_Nothing)
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070064 return "/dev/null";
65
66 std::string OutputFile(OutputDir);
67
Stephen Hines7f5704e2014-06-10 18:06:50 -070068 // Append '/' to Opts.mBitcodeOutputDir if not presents
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070069 if (!OutputFile.empty() &&
Raphael8d5a2f62011-02-08 00:15:05 -080070 (OutputFile[OutputFile.size() - 1]) != OS_PATH_SEPARATOR)
71 OutputFile.append(1, OS_PATH_SEPARATOR);
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070072
Stephen Hines9ae18b22014-06-10 23:53:00 -070073 if (!PathSuffix.empty()) {
74 OutputFile.append(PathSuffix);
75 OutputFile.append(1, OS_PATH_SEPARATOR);
76 }
77
Stephen Hinese639eb52010-11-08 19:27:20 -080078 if (OutputType == slang::Slang::OT_Dependency) {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070079 // The build system wants the .d file name stem to be exactly the same as
80 // the source .rs file, instead of the .bc file.
Stephen Hinese639eb52010-11-08 19:27:20 -080081 OutputFile.append(slang::RSSlangReflectUtils::GetFileNameStem(InputFile));
82 } else {
83 OutputFile.append(
84 slang::RSSlangReflectUtils::BCFileNameFromRSFileName(InputFile));
85 }
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070086
Stephen Hinese639eb52010-11-08 19:27:20 -080087 switch (OutputType) {
88 case slang::Slang::OT_Dependency: {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070089 OutputFile.append(".d");
90 break;
91 }
Stephen Hinese639eb52010-11-08 19:27:20 -080092 case slang::Slang::OT_Assembly: {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070093 OutputFile.append(".S");
94 break;
95 }
Stephen Hinese639eb52010-11-08 19:27:20 -080096 case slang::Slang::OT_LLVMAssembly: {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070097 OutputFile.append(".ll");
98 break;
99 }
Stephen Hinese639eb52010-11-08 19:27:20 -0800100 case slang::Slang::OT_Object: {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700101 OutputFile.append(".o");
102 break;
103 }
Stephen Hinese639eb52010-11-08 19:27:20 -0800104 case slang::Slang::OT_Bitcode: {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700105 OutputFile.append(".bc");
106 break;
107 }
Stephen Hinese639eb52010-11-08 19:27:20 -0800108 case slang::Slang::OT_Nothing:
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700109 default: {
Stephen Hines6e6578a2011-02-07 18:05:48 -0800110 slangAssert(false && "Invalid output type!");
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700111 }
112 }
113
114 return SaveStringInSet(SavedStrings, OutputFile);
115}
116
Stephen Hines9ae18b22014-06-10 23:53:00 -0700117typedef std::list<std::pair<const char*, const char*> > NamePairList;
118
119/*
120 * Compile the Inputs.
121 *
122 * Returns 0 on success and nonzero on failure.
123 *
124 * IOFiles - list of (foo.rs, foo.bc) pairs of input/output files.
125 * IOFiles32 - list of input/output pairs for 32-bit compilation.
126 * Inputs - input filenames.
127 * Opts - options controlling compilation.
128 * DiagEngine - Clang diagnostic engine (for creating diagnostics).
129 * DiagClient - Slang diagnostic consumer (collects and displays diagnostics).
130 * SavedStrings - expanded strings copied from argv source input files.
131 *
132 * We populate IOFiles dynamically while working through the list of Inputs.
133 * On any 64-bit compilation, we pass back in the 32-bit pairs of files as
134 * IOFiles32. This allows the 64-bit compiler to later bundle up both the
135 * 32-bit and 64-bit bitcode outputs to be included in the final reflected
136 * source code that is emitted.
137 */
138static int compileFiles(NamePairList *IOFiles, NamePairList *IOFiles32,
139 const llvm::SmallVector<const char*, 16> &Inputs, slang::RSCCOptions &Opts,
140 clang::DiagnosticsEngine *DiagEngine, slang::DiagnosticBuffer *DiagClient,
141 std::set<std::string> *SavedStrings) {
142 NamePairList DepFiles;
143 std::string PathSuffix = "";
Stephen Hines2d504fd2014-08-15 01:52:40 -0700144 bool CompileSecondTimeFor64Bit = false;
Stephen Hines9ae18b22014-06-10 23:53:00 -0700145
146 // In our mixed 32/64-bit path, we need to suffix our files differently for
147 // both 32-bit and 64-bit versions.
148 if (Opts.mEmit3264) {
149 if (Opts.mBitWidth == 64) {
150 PathSuffix = "bc64";
Stephen Hines2d504fd2014-08-15 01:52:40 -0700151 CompileSecondTimeFor64Bit = true;
Stephen Hines9ae18b22014-06-10 23:53:00 -0700152 } else {
153 PathSuffix = "bc32";
154 }
155 }
156
157 for (int i = 0, e = Inputs.size(); i != e; i++) {
158 const char *InputFile = Inputs[i];
159
160 const char *BCOutputFile = DetermineOutputFile(Opts.mBitcodeOutputDir,
161 PathSuffix, InputFile,
Yang Ni18d52a62015-04-28 17:30:51 -0700162 Opts.mOutputType,
Stephen Hines9ae18b22014-06-10 23:53:00 -0700163 *SavedStrings);
164 const char *OutputFile = BCOutputFile;
165
166 if (Opts.mEmitDependency) {
167 // The dependency file is always emitted without a PathSuffix.
168 // Collisions between 32-bit and 64-bit files don't make a difference,
169 // because they share the same sources/dependencies.
170 const char *DepOutputFile =
171 DetermineOutputFile(Opts.mDependencyOutputDir, "", InputFile,
172 slang::Slang::OT_Dependency, *SavedStrings);
173 if (Opts.mOutputType == slang::Slang::OT_Dependency) {
174 OutputFile = DepOutputFile;
175 }
176
177 DepFiles.push_back(std::make_pair(BCOutputFile, DepOutputFile));
178 }
179
180 IOFiles->push_back(std::make_pair(InputFile, OutputFile));
181 }
182
Jean-Luc Brouilletc10bc752015-05-04 23:02:25 -0700183 std::unique_ptr<slang::Slang> Compiler(new slang::Slang());
Stephen Hines9ae18b22014-06-10 23:53:00 -0700184 Compiler->init(Opts.mBitWidth, DiagEngine, DiagClient);
185 int CompileFailed = !Compiler->compile(*IOFiles, *IOFiles32, DepFiles, Opts);
Stephen Hines2d504fd2014-08-15 01:52:40 -0700186 // We suppress warnings (via reset) if we are doing a second compilation.
187 Compiler->reset(CompileSecondTimeFor64Bit);
Stephen Hines9ae18b22014-06-10 23:53:00 -0700188 return CompileFailed;
189}
190
Stephen Hinesba7c6dc2011-09-07 19:57:04 -0700191#define str(s) #s
192#define wrap_str(s) str(s)
193static void llvm_rs_cc_VersionPrinter() {
194 llvm::raw_ostream &OS = llvm::outs();
195 OS << "llvm-rs-cc: Renderscript compiler\n"
196 << " (http://developer.android.com/guide/topics/renderscript)\n"
197 << " based on LLVM (http://llvm.org):\n";
198 OS << " Built " << __DATE__ << " (" << __TIME__ ").\n";
199 OS << " Target APIs: " << SLANG_MINIMUM_TARGET_API << " - "
200 << SLANG_MAXIMUM_TARGET_API;
201 OS << "\n Build type: " << wrap_str(TARGET_BUILD_VARIANT);
202#ifndef __DISABLE_ASSERTS
203 OS << " with assertions";
204#endif
205 OS << ".\n";
Stephen Hinesba7c6dc2011-09-07 19:57:04 -0700206}
Stephen Hines8f4d9722011-12-05 14:14:42 -0800207#undef wrap_str
208#undef str
Stephen Hinesba7c6dc2011-09-07 19:57:04 -0700209
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700210int main(int argc, const char **argv) {
211 std::set<std::string> SavedStrings;
212 llvm::SmallVector<const char*, 256> ArgVector;
Stephen Hines8b5c5c62014-06-06 18:03:18 -0700213 slang::RSCCOptions Opts;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700214 llvm::SmallVector<const char*, 16> Inputs;
215 std::string Argv0;
216
Stephen Hines9ae18b22014-06-10 23:53:00 -0700217 llvm::llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700218
219 ExpandArgv(argc, argv, ArgVector, SavedStrings);
220
221 // Argv0
Logan Chien6f4e0a92011-03-10 01:10:25 +0800222 Argv0 = llvm::sys::path::stem(ArgVector[0]);
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700223
224 // Setup diagnostic engine
Stephen Hines8f4d9722011-12-05 14:14:42 -0800225 slang::DiagnosticBuffer *DiagClient = new slang::DiagnosticBuffer();
Loganbe274822011-02-16 22:02:54 +0800226
227 llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs(
228 new clang::DiagnosticIDs());
229
Stephen Hines23c43582013-01-09 20:02:04 -0800230 llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts(
231 new clang::DiagnosticOptions());
232 clang::DiagnosticsEngine DiagEngine(DiagIDs, &*DiagOpts, DiagClient, true);
Logan Chien9207a2e2011-10-21 15:39:28 +0800233
Stephen Hinese639eb52010-11-08 19:27:20 -0800234 slang::Slang::GlobalInitialization();
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700235
Stephen Hines8b5c5c62014-06-06 18:03:18 -0700236 slang::ParseArguments(ArgVector, Inputs, Opts, DiagEngine);
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700237
238 // Exits when there's any error occurred during parsing the arguments
Stephen Hines8f4d9722011-12-05 14:14:42 -0800239 if (DiagEngine.hasErrorOccurred()) {
240 llvm::errs() << DiagClient->str();
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700241 return 1;
Stephen Hines8f4d9722011-12-05 14:14:42 -0800242 }
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700243
244 if (Opts.mShowHelp) {
Stephen Hines7ac9d0d2014-07-15 16:50:03 -0700245 std::unique_ptr<llvm::opt::OptTable> OptTbl(slang::createRSCCOptTable());
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700246 OptTbl->PrintHelp(llvm::outs(), Argv0.c_str(),
Stephen Hinesb7d12692011-09-02 18:16:19 -0700247 "Renderscript source compiler");
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700248 return 0;
249 }
250
251 if (Opts.mShowVersion) {
Stephen Hinesba7c6dc2011-09-07 19:57:04 -0700252 llvm_rs_cc_VersionPrinter();
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700253 return 0;
254 }
255
256 // No input file
257 if (Inputs.empty()) {
Logan Chien9207a2e2011-10-21 15:39:28 +0800258 DiagEngine.Report(clang::diag::err_drv_no_input_files);
Stephen Hines8f4d9722011-12-05 14:14:42 -0800259 llvm::errs() << DiagClient->str();
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700260 return 1;
261 }
262
Zonr Changcf6af6a2010-10-12 12:38:51 +0800263 // Prepare input data for RS compiler.
Stephen Hines9ae18b22014-06-10 23:53:00 -0700264 NamePairList IOFiles64;
265 NamePairList IOFiles32;
Zonr Changcf6af6a2010-10-12 12:38:51 +0800266
Stephen Hines9ae18b22014-06-10 23:53:00 -0700267 int CompileFailed = compileFiles(&IOFiles32, &IOFiles32, Inputs, Opts,
268 &DiagEngine, DiagClient, &SavedStrings);
Zonr Chang641558f2010-10-12 21:07:06 +0800269
Stephen Hines9ae18b22014-06-10 23:53:00 -0700270 // Handle the 64-bit case too!
271 if (Opts.mEmit3264 && !CompileFailed) {
272 Opts.mBitWidth = 64;
273 CompileFailed = compileFiles(&IOFiles64, &IOFiles32, Inputs, Opts,
274 &DiagEngine, DiagClient, &SavedStrings);
Zonr Changcf6af6a2010-10-12 12:38:51 +0800275 }
276
Stephen Hinesd7f0ea22011-02-22 17:45:19 -0800277 return CompileFailed;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700278}
279
280///////////////////////////////////////////////////////////////////////////////
281
282// ExpandArgsFromBuf -
283static void ExpandArgsFromBuf(const char *Arg,
284 llvm::SmallVectorImpl<const char*> &ArgVector,
285 std::set<std::string> &SavedStrings) {
286 const char *FName = Arg + 1;
Stephen Hines7ac9d0d2014-07-15 16:50:03 -0700287 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MBOrErr =
288 llvm::MemoryBuffer::getFile(FName);
289 if (MBOrErr.getError()) {
Loganbe274822011-02-16 22:02:54 +0800290 // Unable to open the file
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700291 ArgVector.push_back(SaveStringInSet(SavedStrings, Arg));
292 return;
293 }
Stephen Hines7ac9d0d2014-07-15 16:50:03 -0700294 std::unique_ptr<llvm::MemoryBuffer> MemBuf = std::move(MBOrErr.get());
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700295
296 const char *Buf = MemBuf->getBufferStart();
297 char InQuote = ' ';
298 std::string CurArg;
299
300 for (const char *P = Buf; ; ++P) {
301 if (*P == '\0' || (isspace(*P) && InQuote == ' ')) {
302 if (!CurArg.empty()) {
303 if (CurArg[0] != '@') {
304 ArgVector.push_back(SaveStringInSet(SavedStrings, CurArg));
305 } else {
306 ExpandArgsFromBuf(CurArg.c_str(), ArgVector, SavedStrings);
307 }
308
309 CurArg = "";
310 }
311 if (*P == '\0')
312 break;
313 else
314 continue;
315 }
316
317 if (isspace(*P)) {
318 if (InQuote != ' ')
319 CurArg.push_back(*P);
320 continue;
321 }
322
323 if (*P == '"' || *P == '\'') {
324 if (InQuote == *P)
325 InQuote = ' ';
326 else if (InQuote == ' ')
327 InQuote = *P;
328 else
329 CurArg.push_back(*P);
330 continue;
331 }
332
333 if (*P == '\\') {
334 ++P;
335 if (*P != '\0')
336 CurArg.push_back(*P);
337 continue;
338 }
339 CurArg.push_back(*P);
340 }
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700341}
342
343// ExpandArgsFromBuf -
344static void ExpandArgv(int argc, const char **argv,
345 llvm::SmallVectorImpl<const char*> &ArgVector,
346 std::set<std::string> &SavedStrings) {
347 for (int i = 0; i < argc; ++i) {
348 const char *Arg = argv[i];
349 if (Arg[0] != '@') {
350 ArgVector.push_back(SaveStringInSet(SavedStrings, std::string(Arg)));
351 continue;
352 }
353
354 ExpandArgsFromBuf(Arg, ArgVector, SavedStrings);
355 }
356}