CodeGenAction.cpp revision 210008
1//===--- CodeGenAction.cpp - LLVM Code Generation Frontend Action ---------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "clang/CodeGen/CodeGenAction.h"
11#include "clang/Basic/SourceManager.h"
12#include "clang/Basic/TargetInfo.h"
13#include "clang/AST/ASTConsumer.h"
14#include "clang/AST/ASTContext.h"
15#include "clang/AST/DeclGroup.h"
16#include "clang/CodeGen/BackendUtil.h"
17#include "clang/CodeGen/ModuleBuilder.h"
18#include "clang/Frontend/CompilerInstance.h"
19#include "clang/Frontend/FrontendDiagnostic.h"
20#include "llvm/LLVMContext.h"
21#include "llvm/Module.h"
22#include "llvm/Pass.h"
23#include "llvm/ADT/OwningPtr.h"
24#include "llvm/Support/IRReader.h"
25#include "llvm/Support/MemoryBuffer.h"
26#include "llvm/Support/SourceMgr.h"
27#include "llvm/Support/Timer.h"
28using namespace clang;
29using namespace llvm;
30
31namespace {
32  class BackendConsumer : public ASTConsumer {
33    Diagnostic &Diags;
34    BackendAction Action;
35    const CodeGenOptions &CodeGenOpts;
36    const TargetOptions &TargetOpts;
37    llvm::raw_ostream *AsmOutStream;
38    ASTContext *Context;
39
40    Timer LLVMIRGeneration;
41
42    llvm::OwningPtr<CodeGenerator> Gen;
43
44    llvm::OwningPtr<llvm::Module> TheModule;
45
46  public:
47    BackendConsumer(BackendAction action, Diagnostic &_Diags,
48                    const CodeGenOptions &compopts,
49                    const TargetOptions &targetopts, bool TimePasses,
50                    const std::string &infile, llvm::raw_ostream *OS,
51                    LLVMContext &C) :
52      Diags(_Diags),
53      Action(action),
54      CodeGenOpts(compopts),
55      TargetOpts(targetopts),
56      AsmOutStream(OS),
57      LLVMIRGeneration("LLVM IR Generation Time"),
58      Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)) {
59      llvm::TimePassesIsEnabled = TimePasses;
60    }
61
62    llvm::Module *takeModule() { return TheModule.take(); }
63
64    virtual void Initialize(ASTContext &Ctx) {
65      Context = &Ctx;
66
67      if (llvm::TimePassesIsEnabled)
68        LLVMIRGeneration.startTimer();
69
70      Gen->Initialize(Ctx);
71
72      TheModule.reset(Gen->GetModule());
73
74      if (llvm::TimePassesIsEnabled)
75        LLVMIRGeneration.stopTimer();
76    }
77
78    virtual void HandleTopLevelDecl(DeclGroupRef D) {
79      PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(),
80                                     Context->getSourceManager(),
81                                     "LLVM IR generation of declaration");
82
83      if (llvm::TimePassesIsEnabled)
84        LLVMIRGeneration.startTimer();
85
86      Gen->HandleTopLevelDecl(D);
87
88      if (llvm::TimePassesIsEnabled)
89        LLVMIRGeneration.stopTimer();
90    }
91
92    virtual void HandleTranslationUnit(ASTContext &C) {
93      {
94        PrettyStackTraceString CrashInfo("Per-file LLVM IR generation");
95        if (llvm::TimePassesIsEnabled)
96          LLVMIRGeneration.startTimer();
97
98        Gen->HandleTranslationUnit(C);
99
100        if (llvm::TimePassesIsEnabled)
101          LLVMIRGeneration.stopTimer();
102      }
103
104      // Silently ignore if we weren't initialized for some reason.
105      if (!TheModule)
106        return;
107
108      // Make sure IR generation is happy with the module. This is released by
109      // the module provider.
110      Module *M = Gen->ReleaseModule();
111      if (!M) {
112        // The module has been released by IR gen on failures, do not double
113        // free.
114        TheModule.take();
115        return;
116      }
117
118      assert(TheModule.get() == M &&
119             "Unexpected module change during IR generation");
120
121      // Install an inline asm handler so that diagnostics get printed through
122      // our diagnostics hooks.
123      LLVMContext &Ctx = TheModule->getContext();
124      void *OldHandler = Ctx.getInlineAsmDiagnosticHandler();
125      void *OldContext = Ctx.getInlineAsmDiagnosticContext();
126      Ctx.setInlineAsmDiagnosticHandler((void*)(intptr_t)InlineAsmDiagHandler,
127                                        this);
128
129      EmitBackendOutput(Diags, CodeGenOpts, TargetOpts,
130                        TheModule.get(), Action, AsmOutStream);
131
132      Ctx.setInlineAsmDiagnosticHandler(OldHandler, OldContext);
133    }
134
135    virtual void HandleTagDeclDefinition(TagDecl *D) {
136      PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
137                                     Context->getSourceManager(),
138                                     "LLVM IR generation of declaration");
139      Gen->HandleTagDeclDefinition(D);
140    }
141
142    virtual void CompleteTentativeDefinition(VarDecl *D) {
143      Gen->CompleteTentativeDefinition(D);
144    }
145
146    virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {
147      Gen->HandleVTable(RD, DefinitionRequired);
148    }
149
150    static void InlineAsmDiagHandler(const llvm::SMDiagnostic &SM,void *Context,
151                                     unsigned LocCookie) {
152      SourceLocation Loc = SourceLocation::getFromRawEncoding(LocCookie);
153      ((BackendConsumer*)Context)->InlineAsmDiagHandler2(SM, Loc);
154    }
155
156    void InlineAsmDiagHandler2(const llvm::SMDiagnostic &,
157                               SourceLocation LocCookie);
158  };
159}
160
161/// ConvertBackendLocation - Convert a location in a temporary llvm::SourceMgr
162/// buffer to be a valid FullSourceLoc.
163static FullSourceLoc ConvertBackendLocation(const llvm::SMDiagnostic &D,
164                                            SourceManager &CSM) {
165  // Get both the clang and llvm source managers.  The location is relative to
166  // a memory buffer that the LLVM Source Manager is handling, we need to add
167  // a copy to the Clang source manager.
168  const llvm::SourceMgr &LSM = *D.getSourceMgr();
169
170  // We need to copy the underlying LLVM memory buffer because llvm::SourceMgr
171  // already owns its one and clang::SourceManager wants to own its one.
172  const MemoryBuffer *LBuf =
173  LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
174
175  // Create the copy and transfer ownership to clang::SourceManager.
176  llvm::MemoryBuffer *CBuf =
177  llvm::MemoryBuffer::getMemBufferCopy(LBuf->getBuffer(),
178                                       LBuf->getBufferIdentifier());
179  FileID FID = CSM.createFileIDForMemBuffer(CBuf);
180
181  // Translate the offset into the file.
182  unsigned Offset = D.getLoc().getPointer()  - LBuf->getBufferStart();
183  SourceLocation NewLoc =
184  CSM.getLocForStartOfFile(FID).getFileLocWithOffset(Offset);
185  return FullSourceLoc(NewLoc, CSM);
186}
187
188
189/// InlineAsmDiagHandler2 - This function is invoked when the backend hits an
190/// error parsing inline asm.  The SMDiagnostic indicates the error relative to
191/// the temporary memory buffer that the inline asm parser has set up.
192void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D,
193                                            SourceLocation LocCookie) {
194  // There are a couple of different kinds of errors we could get here.  First,
195  // we re-format the SMDiagnostic in terms of a clang diagnostic.
196
197  // Strip "error: " off the start of the message string.
198  llvm::StringRef Message = D.getMessage();
199  if (Message.startswith("error: "))
200    Message = Message.substr(7);
201
202  // If the SMDiagnostic has an inline asm source location, translate it.
203  FullSourceLoc Loc;
204  if (D.getLoc() != SMLoc())
205    Loc = ConvertBackendLocation(D, Context->getSourceManager());
206
207
208  // If this problem has clang-level source location information, report the
209  // issue as being an error in the source with a note showing the instantiated
210  // code.
211  if (LocCookie.isValid()) {
212    Diags.Report(FullSourceLoc(LocCookie, Context->getSourceManager()),
213                 diag::err_fe_inline_asm).AddString(Message);
214
215    if (D.getLoc().isValid())
216      Diags.Report(Loc, diag::note_fe_inline_asm_here);
217    return;
218  }
219
220  // Otherwise, report the backend error as occuring in the generated .s file.
221  // If Loc is invalid, we still need to report the error, it just gets no
222  // location info.
223  Diags.Report(Loc, diag::err_fe_inline_asm).AddString(Message);
224}
225
226//
227
228CodeGenAction::CodeGenAction(unsigned _Act) : Act(_Act) {}
229
230CodeGenAction::~CodeGenAction() {}
231
232bool CodeGenAction::hasIRSupport() const { return true; }
233
234void CodeGenAction::EndSourceFileAction() {
235  // If the consumer creation failed, do nothing.
236  if (!getCompilerInstance().hasASTConsumer())
237    return;
238
239  // Steal the module from the consumer.
240  BackendConsumer *Consumer = static_cast<BackendConsumer*>(
241    &getCompilerInstance().getASTConsumer());
242
243  TheModule.reset(Consumer->takeModule());
244}
245
246llvm::Module *CodeGenAction::takeModule() {
247  return TheModule.take();
248}
249
250static raw_ostream *GetOutputStream(CompilerInstance &CI,
251                                    llvm::StringRef InFile,
252                                    BackendAction Action) {
253  switch (Action) {
254  case Backend_EmitAssembly:
255    return CI.createDefaultOutputFile(false, InFile, "s");
256  case Backend_EmitLL:
257    return CI.createDefaultOutputFile(false, InFile, "ll");
258  case Backend_EmitBC:
259    return CI.createDefaultOutputFile(true, InFile, "bc");
260  case Backend_EmitNothing:
261    return 0;
262  case Backend_EmitMCNull:
263  case Backend_EmitObj:
264    return CI.createDefaultOutputFile(true, InFile, "o");
265  }
266
267  assert(0 && "Invalid action!");
268  return 0;
269}
270
271ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI,
272                                              llvm::StringRef InFile) {
273  BackendAction BA = static_cast<BackendAction>(Act);
274  llvm::OwningPtr<llvm::raw_ostream> OS(GetOutputStream(CI, InFile, BA));
275  if (BA != Backend_EmitNothing && !OS)
276    return 0;
277
278  return new BackendConsumer(BA, CI.getDiagnostics(),
279                             CI.getCodeGenOpts(), CI.getTargetOpts(),
280                             CI.getFrontendOpts().ShowTimers, InFile, OS.take(),
281                             CI.getLLVMContext());
282}
283
284void CodeGenAction::ExecuteAction() {
285  // If this is an IR file, we have to treat it specially.
286  if (getCurrentFileKind() == IK_LLVM_IR) {
287    BackendAction BA = static_cast<BackendAction>(Act);
288    CompilerInstance &CI = getCompilerInstance();
289    raw_ostream *OS = GetOutputStream(CI, getCurrentFile(), BA);
290    if (BA != Backend_EmitNothing && !OS)
291      return;
292
293    bool Invalid;
294    SourceManager &SM = CI.getSourceManager();
295    const llvm::MemoryBuffer *MainFile = SM.getBuffer(SM.getMainFileID(),
296                                                      &Invalid);
297    if (Invalid)
298      return;
299
300    // FIXME: This is stupid, IRReader shouldn't take ownership.
301    llvm::MemoryBuffer *MainFileCopy =
302      llvm::MemoryBuffer::getMemBufferCopy(MainFile->getBuffer(),
303                                           getCurrentFile().c_str());
304
305    llvm::SMDiagnostic Err;
306    TheModule.reset(ParseIR(MainFileCopy, Err, CI.getLLVMContext()));
307    if (!TheModule) {
308      // Translate from the diagnostic info to the SourceManager location.
309      SourceLocation Loc = SM.getLocation(
310        SM.getFileEntryForID(SM.getMainFileID()), Err.getLineNo(),
311        Err.getColumnNo() + 1);
312
313      // Get a custom diagnostic for the error. We strip off a leading
314      // diagnostic code if there is one.
315      llvm::StringRef Msg = Err.getMessage();
316      if (Msg.startswith("error: "))
317        Msg = Msg.substr(7);
318      unsigned DiagID = CI.getDiagnostics().getCustomDiagID(Diagnostic::Error,
319                                                            Msg);
320
321      CI.getDiagnostics().Report(FullSourceLoc(Loc, SM), DiagID);
322      return;
323    }
324
325    EmitBackendOutput(CI.getDiagnostics(), CI.getCodeGenOpts(),
326                      CI.getTargetOpts(), TheModule.get(),
327                      BA, OS);
328    return;
329  }
330
331  // Otherwise follow the normal AST path.
332  this->ASTFrontendAction::ExecuteAction();
333}
334
335//
336
337EmitAssemblyAction::EmitAssemblyAction()
338  : CodeGenAction(Backend_EmitAssembly) {}
339
340EmitBCAction::EmitBCAction() : CodeGenAction(Backend_EmitBC) {}
341
342EmitLLVMAction::EmitLLVMAction() : CodeGenAction(Backend_EmitLL) {}
343
344EmitLLVMOnlyAction::EmitLLVMOnlyAction() : CodeGenAction(Backend_EmitNothing) {}
345
346EmitCodeGenOnlyAction::EmitCodeGenOnlyAction() : CodeGenAction(Backend_EmitMCNull) {}
347
348EmitObjAction::EmitObjAction() : CodeGenAction(Backend_EmitObj) {}
349