1 /*
2 * Copyright 2010, 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 "slang.h"
18
19 #include <stdlib.h>
20
21 #include <string>
22 #include <vector>
23
24 #include "clang/AST/ASTConsumer.h"
25 #include "clang/AST/ASTContext.h"
26
27 #include "clang/Basic/DiagnosticIDs.h"
28 #include "clang/Basic/DiagnosticOptions.h"
29 #include "clang/Basic/FileManager.h"
30 #include "clang/Basic/FileSystemOptions.h"
31 #include "clang/Basic/LangOptions.h"
32 #include "clang/Basic/SourceManager.h"
33 #include "clang/Basic/TargetInfo.h"
34 #include "clang/Basic/TargetOptions.h"
35
36 #include "clang/Frontend/CodeGenOptions.h"
37 #include "clang/Frontend/DependencyOutputOptions.h"
38 #include "clang/Frontend/FrontendDiagnostic.h"
39 #include "clang/Frontend/TextDiagnosticPrinter.h"
40 #include "clang/Frontend/Utils.h"
41
42 #include "clang/Lex/Preprocessor.h"
43 #include "clang/Lex/PreprocessorOptions.h"
44 #include "clang/Lex/HeaderSearch.h"
45 #include "clang/Lex/HeaderSearchOptions.h"
46
47 #include "clang/Parse/ParseAST.h"
48
49 #include "llvm/ADT/IntrusiveRefCntPtr.h"
50
51 #include "llvm/Bitcode/ReaderWriter.h"
52
53 // More force linking
54 #include "llvm/Linker.h"
55
56 // Force linking all passes/vmcore stuffs to libslang.so
57 #include "llvm/LinkAllIR.h"
58 #include "llvm/LinkAllPasses.h"
59
60 #include "llvm/Support/raw_ostream.h"
61 #include "llvm/Support/MemoryBuffer.h"
62 #include "llvm/Support/ErrorHandling.h"
63 #include "llvm/Support/ManagedStatic.h"
64 #include "llvm/Support/Path.h"
65 #include "llvm/Support/TargetSelect.h"
66 #include "llvm/Support/ToolOutputFile.h"
67
68 #include "slang_assert.h"
69 #include "slang_backend.h"
70 #include "slang_utils.h"
71
72 namespace {
73
74 struct ForceSlangLinking {
ForceSlangLinking__anon19b69e5b0111::ForceSlangLinking75 ForceSlangLinking() {
76 // We must reference the functions in such a way that compilers will not
77 // delete it all as dead code, even with whole program optimization,
78 // yet is effectively a NO-OP. As the compiler isn't smart enough
79 // to know that getenv() never returns -1, this will do the job.
80 if (std::getenv("bar") != reinterpret_cast<char*>(-1))
81 return;
82
83 // llvm-rs-link needs following functions existing in libslang.
84 llvm::ParseBitcodeFile(NULL, llvm::getGlobalContext(), NULL);
85 llvm::Linker::LinkModules(NULL, NULL, 0, NULL);
86
87 // llvm-rs-cc need this.
88 new clang::TextDiagnosticPrinter(llvm::errs(),
89 new clang::DiagnosticOptions());
90 }
91 } ForceSlangLinking;
92
93 } // namespace
94
95 namespace slang {
96
97 #if defined(__arm__)
98 # define DEFAULT_TARGET_TRIPLE_STRING "armv7-none-linux-gnueabi"
99 #elif defined(__x86_64__)
100 # define DEFAULT_TARGET_TRIPLE_STRING "x86_64-unknown-linux"
101 #else
102 // let's use x86 as default target
103 # define DEFAULT_TARGET_TRIPLE_STRING "i686-unknown-linux"
104 #endif
105
106 bool Slang::GlobalInitialized = false;
107
108 // Language option (define the language feature for compiler such as C99)
109 clang::LangOptions Slang::LangOpts;
110
111 // Code generation option for the compiler
112 clang::CodeGenOptions Slang::CodeGenOpts;
113
114 // The named of metadata node that pragma resides (should be synced with
115 // bcc.cpp)
116 const llvm::StringRef Slang::PragmaMetadataName = "#pragma";
117
118 static inline llvm::tool_output_file *
OpenOutputFile(const char * OutputFile,llvm::sys::fs::OpenFlags Flags,std::string * Error,clang::DiagnosticsEngine * DiagEngine)119 OpenOutputFile(const char *OutputFile,
120 llvm::sys::fs::OpenFlags Flags,
121 std::string* Error,
122 clang::DiagnosticsEngine *DiagEngine) {
123 slangAssert((OutputFile != NULL) && (Error != NULL) &&
124 (DiagEngine != NULL) && "Invalid parameter!");
125
126 if (SlangUtils::CreateDirectoryWithParents(
127 llvm::sys::path::parent_path(OutputFile), Error)) {
128 llvm::tool_output_file *F =
129 new llvm::tool_output_file(OutputFile, *Error, Flags);
130 if (F != NULL)
131 return F;
132 }
133
134 // Report error here.
135 DiagEngine->Report(clang::diag::err_fe_error_opening)
136 << OutputFile << *Error;
137
138 return NULL;
139 }
140
GlobalInitialization()141 void Slang::GlobalInitialization() {
142 if (!GlobalInitialized) {
143 // We only support x86, x64 and ARM target
144
145 // For ARM
146 LLVMInitializeARMTargetInfo();
147 LLVMInitializeARMTarget();
148 LLVMInitializeARMAsmPrinter();
149
150 // For x86 and x64
151 LLVMInitializeX86TargetInfo();
152 LLVMInitializeX86Target();
153 LLVMInitializeX86AsmPrinter();
154
155 // Please refer to include/clang/Basic/LangOptions.h to setup
156 // the options.
157 LangOpts.RTTI = 0; // Turn off the RTTI information support
158 LangOpts.C99 = 1;
159 LangOpts.Renderscript = 1;
160 LangOpts.LaxVectorConversions = 0; // Do not bitcast vectors!
161 LangOpts.CharIsSigned = 1; // Signed char is our default.
162
163 CodeGenOpts.OptimizationLevel = 3;
164
165 GlobalInitialized = true;
166 }
167 }
168
LLVMErrorHandler(void * UserData,const std::string & Message,bool GenCrashDialog)169 void Slang::LLVMErrorHandler(void *UserData, const std::string &Message,
170 bool GenCrashDialog) {
171 clang::DiagnosticsEngine* DiagEngine =
172 static_cast<clang::DiagnosticsEngine *>(UserData);
173
174 DiagEngine->Report(clang::diag::err_fe_error_backend) << Message;
175 exit(1);
176 }
177
createTarget(const std::string & Triple,const std::string & CPU,const std::vector<std::string> & Features)178 void Slang::createTarget(const std::string &Triple, const std::string &CPU,
179 const std::vector<std::string> &Features) {
180 if (!Triple.empty())
181 mTargetOpts->Triple = Triple;
182 else
183 mTargetOpts->Triple = DEFAULT_TARGET_TRIPLE_STRING;
184
185 if (!CPU.empty())
186 mTargetOpts->CPU = CPU;
187
188 if (!Features.empty())
189 mTargetOpts->FeaturesAsWritten = Features;
190
191 mTarget.reset(clang::TargetInfo::CreateTargetInfo(*mDiagEngine,
192 mTargetOpts.getPtr()));
193 }
194
createFileManager()195 void Slang::createFileManager() {
196 mFileSysOpt.reset(new clang::FileSystemOptions());
197 mFileMgr.reset(new clang::FileManager(*mFileSysOpt));
198 }
199
createSourceManager()200 void Slang::createSourceManager() {
201 mSourceMgr.reset(new clang::SourceManager(*mDiagEngine, *mFileMgr));
202 }
203
createPreprocessor()204 void Slang::createPreprocessor() {
205 // Default only search header file in current dir
206 llvm::IntrusiveRefCntPtr<clang::HeaderSearchOptions> HSOpts =
207 new clang::HeaderSearchOptions();
208 clang::HeaderSearch *HeaderInfo = new clang::HeaderSearch(HSOpts,
209 *mFileMgr,
210 *mDiagEngine,
211 LangOpts,
212 mTarget.get());
213
214 llvm::IntrusiveRefCntPtr<clang::PreprocessorOptions> PPOpts =
215 new clang::PreprocessorOptions();
216 mPP.reset(new clang::Preprocessor(PPOpts,
217 *mDiagEngine,
218 LangOpts,
219 mTarget.get(),
220 *mSourceMgr,
221 *HeaderInfo,
222 *this,
223 NULL,
224 /* OwnsHeaderSearch = */true));
225 // Initialize the preprocessor
226 mPragmas.clear();
227 mPP->AddPragmaHandler(new PragmaRecorder(&mPragmas));
228
229 std::vector<clang::DirectoryLookup> SearchList;
230 for (unsigned i = 0, e = mIncludePaths.size(); i != e; i++) {
231 if (const clang::DirectoryEntry *DE =
232 mFileMgr->getDirectory(mIncludePaths[i])) {
233 SearchList.push_back(clang::DirectoryLookup(DE,
234 clang::SrcMgr::C_System,
235 false));
236 }
237 }
238
239 HeaderInfo->SetSearchPaths(SearchList,
240 /* angledDirIdx = */1,
241 /* systemDixIdx = */1,
242 /* noCurDirSearch = */false);
243
244 initPreprocessor();
245 }
246
createASTContext()247 void Slang::createASTContext() {
248 mASTContext.reset(new clang::ASTContext(LangOpts,
249 *mSourceMgr,
250 mTarget.get(),
251 mPP->getIdentifierTable(),
252 mPP->getSelectorTable(),
253 mPP->getBuiltinInfo(),
254 /* size_reserve = */0));
255 initASTContext();
256 }
257
258 clang::ASTConsumer *
createBackend(const clang::CodeGenOptions & CodeGenOpts,llvm::raw_ostream * OS,OutputType OT)259 Slang::createBackend(const clang::CodeGenOptions& CodeGenOpts,
260 llvm::raw_ostream *OS, OutputType OT) {
261 return new Backend(mDiagEngine, CodeGenOpts, getTargetOptions(),
262 &mPragmas, OS, OT);
263 }
264
Slang()265 Slang::Slang() : mInitialized(false), mDiagClient(NULL), mOT(OT_Default) {
266 mTargetOpts = new clang::TargetOptions();
267 GlobalInitialization();
268 }
269
init(const std::string & Triple,const std::string & CPU,const std::vector<std::string> & Features,clang::DiagnosticsEngine * DiagEngine,DiagnosticBuffer * DiagClient)270 void Slang::init(const std::string &Triple, const std::string &CPU,
271 const std::vector<std::string> &Features,
272 clang::DiagnosticsEngine *DiagEngine,
273 DiagnosticBuffer *DiagClient) {
274 if (mInitialized)
275 return;
276
277 mDiagEngine = DiagEngine;
278 mDiagClient = DiagClient;
279 mDiag.reset(new clang::Diagnostic(mDiagEngine));
280 initDiagnostic();
281 llvm::install_fatal_error_handler(LLVMErrorHandler, mDiagEngine);
282
283 createTarget(Triple, CPU, Features);
284 createFileManager();
285 createSourceManager();
286
287 mInitialized = true;
288 }
289
loadModule(clang::SourceLocation ImportLoc,clang::ModuleIdPath Path,clang::Module::NameVisibilityKind Visibility,bool IsInclusionDirective)290 clang::ModuleLoadResult Slang::loadModule(
291 clang::SourceLocation ImportLoc,
292 clang::ModuleIdPath Path,
293 clang::Module::NameVisibilityKind Visibility,
294 bool IsInclusionDirective) {
295 slangAssert(0 && "Not implemented");
296 return clang::ModuleLoadResult();
297 }
298
setInputSource(llvm::StringRef InputFile,const char * Text,size_t TextLength)299 bool Slang::setInputSource(llvm::StringRef InputFile,
300 const char *Text,
301 size_t TextLength) {
302 mInputFileName = InputFile.str();
303
304 // Reset the ID tables if we are reusing the SourceManager
305 mSourceMgr->clearIDTables();
306
307 // Load the source
308 llvm::MemoryBuffer *SB =
309 llvm::MemoryBuffer::getMemBuffer(Text, Text + TextLength);
310 mSourceMgr->createMainFileIDForMemBuffer(SB);
311
312 if (mSourceMgr->getMainFileID().isInvalid()) {
313 mDiagEngine->Report(clang::diag::err_fe_error_reading) << InputFile;
314 return false;
315 }
316 return true;
317 }
318
setInputSource(llvm::StringRef InputFile)319 bool Slang::setInputSource(llvm::StringRef InputFile) {
320 mInputFileName = InputFile.str();
321
322 mSourceMgr->clearIDTables();
323
324 const clang::FileEntry *File = mFileMgr->getFile(InputFile);
325 if (File)
326 mSourceMgr->createMainFileID(File);
327
328 if (mSourceMgr->getMainFileID().isInvalid()) {
329 mDiagEngine->Report(clang::diag::err_fe_error_reading) << InputFile;
330 return false;
331 }
332
333 return true;
334 }
335
setOutput(const char * OutputFile)336 bool Slang::setOutput(const char *OutputFile) {
337 std::string Error;
338 llvm::tool_output_file *OS = NULL;
339
340 switch (mOT) {
341 case OT_Dependency:
342 case OT_Assembly:
343 case OT_LLVMAssembly: {
344 OS = OpenOutputFile(OutputFile, llvm::sys::fs::F_None, &Error,
345 mDiagEngine);
346 break;
347 }
348 case OT_Nothing: {
349 break;
350 }
351 case OT_Object:
352 case OT_Bitcode: {
353 OS = OpenOutputFile(OutputFile, llvm::sys::fs::F_Binary,
354 &Error, mDiagEngine);
355 break;
356 }
357 default: {
358 llvm_unreachable("Unknown compiler output type");
359 }
360 }
361
362 if (!Error.empty())
363 return false;
364
365 mOS.reset(OS);
366
367 mOutputFileName = OutputFile;
368
369 return true;
370 }
371
setDepOutput(const char * OutputFile)372 bool Slang::setDepOutput(const char *OutputFile) {
373 std::string Error;
374
375 mDOS.reset(
376 OpenOutputFile(OutputFile, llvm::sys::fs::F_None, &Error, mDiagEngine));
377 if (!Error.empty() || (mDOS.get() == NULL))
378 return false;
379
380 mDepOutputFileName = OutputFile;
381
382 return true;
383 }
384
generateDepFile()385 int Slang::generateDepFile() {
386 if (mDiagEngine->hasErrorOccurred())
387 return 1;
388 if (mDOS.get() == NULL)
389 return 1;
390
391 // Initialize options for generating dependency file
392 clang::DependencyOutputOptions DepOpts;
393 DepOpts.IncludeSystemHeaders = 1;
394 DepOpts.OutputFile = mDepOutputFileName;
395 DepOpts.Targets = mAdditionalDepTargets;
396 DepOpts.Targets.push_back(mDepTargetBCFileName);
397 for (std::vector<std::string>::const_iterator
398 I = mGeneratedFileNames.begin(), E = mGeneratedFileNames.end();
399 I != E;
400 I++) {
401 DepOpts.Targets.push_back(*I);
402 }
403 mGeneratedFileNames.clear();
404
405 // Per-compilation needed initialization
406 createPreprocessor();
407 AttachDependencyFileGen(*mPP.get(), DepOpts);
408
409 // Inform the diagnostic client we are processing a source file
410 mDiagClient->BeginSourceFile(LangOpts, mPP.get());
411
412 // Go through the source file (no operations necessary)
413 clang::Token Tok;
414 mPP->EnterMainSourceFile();
415 do {
416 mPP->Lex(Tok);
417 } while (Tok.isNot(clang::tok::eof));
418
419 mPP->EndSourceFile();
420
421 // Declare success if no error
422 if (!mDiagEngine->hasErrorOccurred())
423 mDOS->keep();
424
425 // Clean up after compilation
426 mPP.reset();
427 mDOS.reset();
428
429 return mDiagEngine->hasErrorOccurred() ? 1 : 0;
430 }
431
compile()432 int Slang::compile() {
433 if (mDiagEngine->hasErrorOccurred())
434 return 1;
435 if (mOS.get() == NULL)
436 return 1;
437
438 // Here is per-compilation needed initialization
439 createPreprocessor();
440 createASTContext();
441
442 mBackend.reset(createBackend(CodeGenOpts, &mOS->os(), mOT));
443
444 // Inform the diagnostic client we are processing a source file
445 mDiagClient->BeginSourceFile(LangOpts, mPP.get());
446
447 // The core of the slang compiler
448 ParseAST(*mPP, mBackend.get(), *mASTContext);
449
450 // Inform the diagnostic client we are done with previous source file
451 mDiagClient->EndSourceFile();
452
453 // Declare success if no error
454 if (!mDiagEngine->hasErrorOccurred())
455 mOS->keep();
456
457 // The compilation ended, clear
458 mBackend.reset();
459 mASTContext.reset();
460 mPP.reset();
461 mOS.reset();
462
463 return mDiagEngine->hasErrorOccurred() ? 1 : 0;
464 }
465
setDebugMetadataEmission(bool EmitDebug)466 void Slang::setDebugMetadataEmission(bool EmitDebug) {
467 if (EmitDebug)
468 CodeGenOpts.setDebugInfo(clang::CodeGenOptions::FullDebugInfo);
469 else
470 CodeGenOpts.setDebugInfo(clang::CodeGenOptions::NoDebugInfo);
471 }
472
setOptimizationLevel(llvm::CodeGenOpt::Level OptimizationLevel)473 void Slang::setOptimizationLevel(llvm::CodeGenOpt::Level OptimizationLevel) {
474 CodeGenOpts.OptimizationLevel = OptimizationLevel;
475 }
476
reset()477 void Slang::reset() {
478 llvm::errs() << mDiagClient->str();
479 mDiagEngine->Reset();
480 mDiagClient->reset();
481 }
482
~Slang()483 Slang::~Slang() {
484 llvm::llvm_shutdown();
485 }
486
487 } // namespace slang
488