aboutsummaryrefslogtreecommitdiff
path: root/lib/Frontend
diff options
context:
space:
mode:
authorDaniel Dunbar <daniel@zuster.org>2010-06-07 23:27:59 +0000
committerDaniel Dunbar <daniel@zuster.org>2010-06-07 23:27:59 +0000
commit4cbbd94d0abeec2d7e7438d098527aa340d82389 (patch)
tree4f1d5230c0e7fb4930d785897e79bb30bd0b5ea3 /lib/Frontend
parentfaddc3e53a95c68f2c3a966e0f1e6eba110dafd6 (diff)
Frontend: Add CodeGenAction support for handling LLVM IR. - This magically enables using 'clang -cc1' as a replacement for most of 'llvm-as', 'llvm-dis', 'llc' and 'opt' functionality. For example, 'llvm-as' is: $ clang -cc1 -emit-llvm-bc FOO.ll -o FOO.bc
and 'llvm-dis' is: $ clang -cc1 -emit-llvm FOO.bc -o - and 'opt' is, e.g.: $ clang -cc1 -emit-llvm -O3 -o FOO.opt.ll FOO.ll and 'llc' is, e.g.: $ clang -cc1 -S -o - FOO.ll The nice thing about using the backend tools this way is that they are guaranteed to exactly match how the compiler generates code (for example, setting the same backend options). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@105583 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Frontend')
-rw-r--r--lib/Frontend/CodeGenAction.cpp88
1 files changed, 74 insertions, 14 deletions
diff --git a/lib/Frontend/CodeGenAction.cpp b/lib/Frontend/CodeGenAction.cpp
index 99af838a33..22b3bd416d 100644
--- a/lib/Frontend/CodeGenAction.cpp
+++ b/lib/Frontend/CodeGenAction.cpp
@@ -22,6 +22,7 @@
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/IRReader.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/Timer.h"
@@ -220,6 +221,8 @@ CodeGenAction::CodeGenAction(unsigned _Act) : Act(_Act) {}
CodeGenAction::~CodeGenAction() {}
+bool CodeGenAction::hasIRSupport() const { return true; }
+
void CodeGenAction::EndSourceFileAction() {
// If the consumer creation failed, do nothing.
if (!getCompilerInstance().hasASTConsumer())
@@ -236,27 +239,31 @@ llvm::Module *CodeGenAction::takeModule() {
return TheModule.take();
}
-ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
- BackendAction BA = static_cast<BackendAction>(Act);
- llvm::OwningPtr<llvm::raw_ostream> OS;
- switch (BA) {
+static raw_ostream *GetOutputStream(CompilerInstance &CI,
+ llvm::StringRef InFile,
+ BackendAction Action) {
+ switch (Action) {
case Backend_EmitAssembly:
- OS.reset(CI.createDefaultOutputFile(false, InFile, "s"));
- break;
+ return CI.createDefaultOutputFile(false, InFile, "s");
case Backend_EmitLL:
- OS.reset(CI.createDefaultOutputFile(false, InFile, "ll"));
- break;
+ return CI.createDefaultOutputFile(false, InFile, "ll");
case Backend_EmitBC:
- OS.reset(CI.createDefaultOutputFile(true, InFile, "bc"));
- break;
+ return CI.createDefaultOutputFile(true, InFile, "bc");
case Backend_EmitNothing:
- break;
+ return 0;
case Backend_EmitMCNull:
case Backend_EmitObj:
- OS.reset(CI.createDefaultOutputFile(true, InFile, "o"));
- break;
+ return CI.createDefaultOutputFile(true, InFile, "o");
}
+
+ assert(0 && "Invalid action!");
+ return 0;
+}
+
+ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ BackendAction BA = static_cast<BackendAction>(Act);
+ llvm::OwningPtr<llvm::raw_ostream> OS(GetOutputStream(CI, InFile, BA));
if (BA != Backend_EmitNothing && !OS)
return 0;
@@ -266,6 +273,59 @@ ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI,
CI.getLLVMContext());
}
+void CodeGenAction::ExecuteAction() {
+ // If this is an IR file, we have to treat it specially.
+ if (getCurrentFileKind() == IK_LLVM_IR) {
+ BackendAction BA = static_cast<BackendAction>(Act);
+ CompilerInstance &CI = getCompilerInstance();
+ raw_ostream *OS = GetOutputStream(CI, getCurrentFile(), BA);
+ if (BA != Backend_EmitNothing && !OS)
+ return;
+
+ bool Invalid;
+ SourceManager &SM = CI.getSourceManager();
+ const llvm::MemoryBuffer *MainFile = SM.getBuffer(SM.getMainFileID(),
+ &Invalid);
+ if (Invalid)
+ return;
+
+ // FIXME: This is stupid, IRReader shouldn't take ownership.
+ llvm::MemoryBuffer *MainFileCopy =
+ llvm::MemoryBuffer::getMemBufferCopy(MainFile->getBuffer(),
+ getCurrentFile().c_str());
+
+ llvm::SMDiagnostic Err;
+ TheModule.reset(ParseIR(MainFileCopy, Err, CI.getLLVMContext()));
+ if (!TheModule) {
+ // Translate from the diagnostic info to the SourceManager location.
+ SourceLocation Loc = SM.getLocation(
+ SM.getFileEntryForID(SM.getMainFileID()), Err.getLineNo(),
+ Err.getColumnNo() + 1);
+
+ // Get a custom diagnostic for the error. We strip off a leading
+ // diagnostic code if there is one.
+ llvm::StringRef Msg = Err.getMessage();
+ if (Msg.startswith("error: "))
+ Msg = Msg.substr(7);
+ unsigned DiagID = CI.getDiagnostics().getCustomDiagID(Diagnostic::Error,
+ Msg);
+
+ CI.getDiagnostics().Report(FullSourceLoc(Loc, SM), DiagID);
+ return;
+ }
+
+ EmitBackendOutput(CI.getDiagnostics(), CI.getCodeGenOpts(),
+ CI.getTargetOpts(), TheModule.get(),
+ BA, OS);
+ return;
+ }
+
+ // Otherwise follow the normal AST path.
+ this->ASTFrontendAction::ExecuteAction();
+}
+
+//
+
EmitAssemblyAction::EmitAssemblyAction()
: CodeGenAction(Backend_EmitAssembly) {}