1 /* 2 * Copyright 2010-2012, The Android Open Source Project 3 * 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 17 #include "clang/Basic/DiagnosticOptions.h" 18 #include "clang/Driver/DriverDiagnostic.h" 19 #include "clang/Driver/Options.h" 20 #include "clang/Frontend/CompilerInvocation.h" 21 #include "clang/Frontend/FrontendDiagnostic.h" 22 #include "clang/Frontend/TextDiagnosticPrinter.h" 23 #include "clang/Frontend/Utils.h" 24 25 #include "llvm/ADT/SmallVector.h" 26 #include "llvm/ADT/IntrusiveRefCntPtr.h" 27 28 #include "llvm/Option/OptTable.h" 29 #include "llvm/Support/Allocator.h" 30 #include "llvm/Support/ManagedStatic.h" 31 #include "llvm/Support/MemoryBuffer.h" 32 #include "llvm/Support/Path.h" 33 #include "llvm/Support/raw_ostream.h" 34 #include "llvm/Support/Signals.h" 35 #include "llvm/Support/StringSaver.h" 36 #include "llvm/Target/TargetMachine.h" 37 38 #include "os_sep.h" 39 #include "rs_cc_options.h" 40 #include "slang.h" 41 #include "slang_assert.h" 42 #include "slang_diagnostic_buffer.h" 43 #include "slang_rs_reflect_utils.h" 44 45 #include <list> 46 #include <set> 47 #include <string> 48 49 namespace { 50 class StringSet { 51 public: 52 const char *save(const char *Str) { 53 return Strings.save(Str); 54 } 55 56 StringSet() : Strings(A), A() {} 57 58 llvm::StringSaver & getStringSaver() { return Strings; } 59 60 private: 61 llvm::StringSaver Strings; 62 llvm::BumpPtrAllocator A; 63 }; 64 } 65 66 static const char *DetermineOutputFile(const std::string &OutputDir, 67 const std::string &PathSuffix, 68 const char *InputFile, 69 slang::Slang::OutputType OutputType, 70 StringSet *SavedStrings) { 71 if (OutputType == slang::Slang::OT_Nothing) 72 return "/dev/null"; 73 74 std::string OutputFile(OutputDir); 75 76 // Append '/' to Opts.mBitcodeOutputDir if not presents 77 if (!OutputFile.empty() && 78 (OutputFile[OutputFile.size() - 1]) != OS_PATH_SEPARATOR) 79 OutputFile.append(1, OS_PATH_SEPARATOR); 80 81 if (!PathSuffix.empty()) { 82 OutputFile.append(PathSuffix); 83 OutputFile.append(1, OS_PATH_SEPARATOR); 84 } 85 86 if (OutputType == slang::Slang::OT_Dependency) { 87 // The build system wants the .d file name stem to be exactly the same as 88 // the source .rs file, instead of the .bc file. 89 OutputFile.append(slang::RSSlangReflectUtils::GetFileNameStem(InputFile)); 90 } else { 91 OutputFile.append( 92 slang::RSSlangReflectUtils::BCFileNameFromRSFileName(InputFile)); 93 } 94 95 switch (OutputType) { 96 case slang::Slang::OT_Dependency: { 97 OutputFile.append(".d"); 98 break; 99 } 100 case slang::Slang::OT_Assembly: { 101 OutputFile.append(".S"); 102 break; 103 } 104 case slang::Slang::OT_LLVMAssembly: { 105 OutputFile.append(".ll"); 106 break; 107 } 108 case slang::Slang::OT_Object: { 109 OutputFile.append(".o"); 110 break; 111 } 112 case slang::Slang::OT_Bitcode: { 113 OutputFile.append(".bc"); 114 break; 115 } 116 case slang::Slang::OT_Nothing: 117 default: { 118 slangAssert(false && "Invalid output type!"); 119 } 120 } 121 122 return SavedStrings->save(OutputFile.c_str()); 123 } 124 125 typedef std::list<std::pair<const char*, const char*> > NamePairList; 126 127 /* 128 * Compile the Inputs. 129 * 130 * Returns 0 on success and nonzero on failure. 131 * 132 * IOFiles - list of (foo.rs, foo.bc) pairs of input/output files. 133 * IOFiles32 - list of input/output pairs for 32-bit compilation. 134 * Inputs - input filenames. 135 * Opts - options controlling compilation. 136 * DiagEngine - Clang diagnostic engine (for creating diagnostics). 137 * DiagClient - Slang diagnostic consumer (collects and displays diagnostics). 138 * SavedStrings - expanded strings copied from argv source input files. 139 * 140 * We populate IOFiles dynamically while working through the list of Inputs. 141 * On any 64-bit compilation, we pass back in the 32-bit pairs of files as 142 * IOFiles32. This allows the 64-bit compiler to later bundle up both the 143 * 32-bit and 64-bit bitcode outputs to be included in the final reflected 144 * source code that is emitted. 145 */ 146 static void makeFileList(NamePairList *IOFiles, NamePairList *DepFiles, 147 const llvm::SmallVector<const char*, 16> &Inputs, slang::RSCCOptions &Opts, 148 StringSet *SavedStrings) { 149 std::string PathSuffix = ""; 150 // In our mixed 32/64-bit path, we need to suffix our files differently for 151 // both 32-bit and 64-bit versions. 152 if (Opts.mEmit3264) { 153 if (Opts.mBitWidth == 64) { 154 PathSuffix = "bc64"; 155 } else { 156 PathSuffix = "bc32"; 157 } 158 } 159 160 for (int i = 0, e = Inputs.size(); i != e; i++) { 161 const char *InputFile = Inputs[i]; 162 163 const char *BCOutputFile = DetermineOutputFile(Opts.mBitcodeOutputDir, 164 PathSuffix, InputFile, 165 Opts.mOutputType, 166 SavedStrings); 167 const char *OutputFile = BCOutputFile; 168 169 if (Opts.mEmitDependency) { 170 // The dependency file is always emitted without a PathSuffix. 171 // Collisions between 32-bit and 64-bit files don't make a difference, 172 // because they share the same sources/dependencies. 173 const char *DepOutputFile = 174 DetermineOutputFile(Opts.mDependencyOutputDir, "", InputFile, 175 slang::Slang::OT_Dependency, SavedStrings); 176 if (Opts.mOutputType == slang::Slang::OT_Dependency) { 177 OutputFile = DepOutputFile; 178 } 179 180 DepFiles->push_back(std::make_pair(BCOutputFile, DepOutputFile)); 181 } 182 183 IOFiles->push_back(std::make_pair(InputFile, OutputFile)); 184 } 185 } 186 187 #define str(s) #s 188 #define wrap_str(s) str(s) 189 static void llvm_rs_cc_VersionPrinter() { 190 llvm::raw_ostream &OS = llvm::outs(); 191 OS << "llvm-rs-cc: Renderscript compiler\n" 192 << " (http://developer.android.com/guide/topics/renderscript)\n" 193 << " based on LLVM (http://llvm.org):\n"; 194 OS << " Built " << __DATE__ << " (" << __TIME__ ").\n"; 195 OS << " Target APIs: " << SLANG_MINIMUM_TARGET_API << " - " 196 << SLANG_MAXIMUM_TARGET_API; 197 OS << "\n Build type: " << wrap_str(TARGET_BUILD_VARIANT); 198 #ifndef __DISABLE_ASSERTS 199 OS << " with assertions"; 200 #endif 201 OS << ".\n"; 202 } 203 #undef wrap_str 204 #undef str 205 206 static void LLVMErrorHandler(void *UserData, const std::string &Message, 207 bool GenCrashDialog) { 208 clang::DiagnosticsEngine *DiagEngine = 209 static_cast<clang::DiagnosticsEngine *>(UserData); 210 211 DiagEngine->Report(clang::diag::err_fe_error_backend) << Message; 212 213 // Run the interrupt handlers to make sure any special cleanups get done, in 214 // particular that we remove files registered with RemoveFileOnSignal. 215 llvm::sys::RunInterruptHandlers(); 216 217 exit(1); 218 } 219 220 int main(int argc, const char **argv) { 221 llvm::llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 222 LLVMInitializeARMTargetInfo(); 223 LLVMInitializeARMTarget(); 224 LLVMInitializeARMAsmPrinter(); 225 226 StringSet SavedStrings; // Keeps track of strings to be destroyed at the end. 227 228 // Parse the command line arguments and respond to show help & version 229 // commands. 230 llvm::SmallVector<const char *, 16> Inputs; 231 slang::RSCCOptions Opts; 232 llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts = 233 new clang::DiagnosticOptions(); 234 if (!slang::ParseArguments(llvm::makeArrayRef(argv, argc), Inputs, Opts, 235 *DiagOpts, SavedStrings.getStringSaver())) { 236 // Exits when there's any error occurred during parsing the arguments 237 return 1; 238 } 239 if (Opts.mShowHelp) { 240 std::unique_ptr<llvm::opt::OptTable> OptTbl(slang::createRSCCOptTable()); 241 const std::string Argv0 = llvm::sys::path::stem(argv[0]); 242 OptTbl->PrintHelp(llvm::outs(), Argv0.c_str(), 243 "Renderscript source compiler"); 244 return 0; 245 } 246 if (Opts.mShowVersion) { 247 llvm_rs_cc_VersionPrinter(); 248 return 0; 249 } 250 251 // Initialize the diagnostic objects 252 llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs( 253 new clang::DiagnosticIDs()); 254 slang::DiagnosticBuffer DiagsBuffer; 255 clang::DiagnosticsEngine DiagEngine(DiagIDs, &*DiagOpts, &DiagsBuffer, false); 256 clang::ProcessWarningOptions(DiagEngine, *DiagOpts); 257 (void)DiagEngine.setSeverityForGroup(clang::diag::Flavor::WarningOrError, 258 "implicit-function-declaration", 259 clang::diag::Severity::Error); 260 261 // Report error if no input file 262 if (Inputs.empty()) { 263 DiagEngine.Report(clang::diag::err_drv_no_input_files); 264 llvm::errs() << DiagsBuffer.str(); 265 return 1; 266 } 267 268 llvm::install_fatal_error_handler(LLVMErrorHandler, &DiagEngine); 269 270 // Compile the 32 bit version 271 NamePairList IOFiles32; 272 NamePairList DepFiles32; 273 makeFileList(&IOFiles32, &DepFiles32, Inputs, Opts, &SavedStrings); 274 275 int CompileFailed = 0; 276 // Handle 32-bit case for Java and C++ reflection. 277 // For Java, both 32bit and 64bit will be generated. 278 // For C++, either 64bit or 32bit will be generated based on the target. 279 if (Opts.mEmit3264 || Opts.mBitWidth == 32) { 280 std::unique_ptr<slang::Slang> Compiler( 281 new slang::Slang(32, &DiagEngine, &DiagsBuffer)); 282 CompileFailed = 283 !Compiler->compile(IOFiles32, IOFiles32, DepFiles32, Opts, *DiagOpts); 284 } 285 286 // Handle the 64-bit case too! 287 bool needEmit64 = Opts.mEmit3264 || Opts.mBitWidth == 64; 288 if (needEmit64 && !CompileFailed) { 289 Opts.mBitWidth = 64; 290 NamePairList IOFiles64; 291 NamePairList DepFiles64; 292 makeFileList(&IOFiles64, &DepFiles64, Inputs, Opts, &SavedStrings); 293 294 std::unique_ptr<slang::Slang> Compiler( 295 new slang::Slang(64, &DiagEngine, &DiagsBuffer)); 296 CompileFailed = 297 !Compiler->compile(IOFiles64, IOFiles32, DepFiles64, Opts, *DiagOpts); 298 } 299 300 llvm::errs() << DiagsBuffer.str(); 301 llvm::remove_fatal_error_handler(); 302 return CompileFailed; 303 } 304