1 //===-- cc1as_main.cpp - Clang Assembler ---------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This is the entry point to the clang -cc1as functionality, which implements
11 // the direct interface to the LLVM MC based assembler.
13 //===----------------------------------------------------------------------===//
15 #include "clang/Basic/Diagnostic.h"
16 #include "clang/Driver/Arg.h"
17 #include "clang/Driver/ArgList.h"
18 #include "clang/Driver/DriverDiagnostic.h"
19 #include "clang/Driver/CC1AsOptions.h"
20 #include "clang/Driver/OptTable.h"
21 #include "clang/Driver/Options.h"
22 #include "clang/Frontend/DiagnosticOptions.h"
23 #include "clang/Frontend/FrontendDiagnostic.h"
24 #include "clang/Frontend/TextDiagnosticPrinter.h"
25 #include "llvm/ADT/OwningPtr.h"
26 #include "llvm/ADT/StringSwitch.h"
27 #include "llvm/ADT/Triple.h"
28 #include "llvm/MC/MCParser/MCAsmParser.h"
29 #include "llvm/MC/MCAsmInfo.h"
30 #include "llvm/MC/MCCodeEmitter.h"
31 #include "llvm/MC/MCContext.h"
32 #include "llvm/MC/MCStreamer.h"
33 #include "llvm/Support/CommandLine.h"
34 #include "llvm/Support/FormattedStream.h"
35 #include "llvm/Support/ErrorHandling.h"
36 #include "llvm/Support/ManagedStatic.h"
37 #include "llvm/Support/MemoryBuffer.h"
38 #include "llvm/Support/PrettyStackTrace.h"
39 #include "llvm/Support/SourceMgr.h"
40 #include "llvm/Support/Timer.h"
41 #include "llvm/Support/raw_ostream.h"
42 #include "llvm/Support/Host.h"
43 #include "llvm/Support/Path.h"
44 #include "llvm/Support/Signals.h"
45 #include "llvm/Support/system_error.h"
46 #include "llvm/Target/TargetAsmBackend.h"
47 #include "llvm/Target/TargetAsmInfo.h"
48 #include "llvm/Target/TargetAsmParser.h"
49 #include "llvm/Target/TargetData.h"
50 #include "llvm/Target/TargetLowering.h"
51 #include "llvm/Target/TargetLoweringObjectFile.h"
52 #include "llvm/Target/TargetMachine.h"
53 #include "llvm/Target/TargetRegistry.h"
54 #include "llvm/Target/TargetSelect.h"
55 using namespace clang
;
56 using namespace clang::driver
;
61 /// \brief Helper class for representing a single invocation of the assembler.
62 struct AssemblerInvocation
{
63 /// @name Target Options
69 /// @name Language Options
72 std::vector
<std::string
> IncludePaths
;
73 unsigned NoInitialTextSection
: 1;
76 /// @name Frontend Options
79 std::string InputFile
;
80 std::vector
<std::string
> LLVMArgs
;
81 std::string OutputPath
;
83 FT_Asm
, ///< Assembly (.s) output, transliterate mode.
84 FT_Null
, ///< No output, for timing purposes.
85 FT_Obj
///< Object file output.
88 unsigned ShowHelp
: 1;
89 unsigned ShowVersion
: 1;
92 /// @name Transliterate Options
95 unsigned OutputAsmVariant
;
96 unsigned ShowEncoding
: 1;
97 unsigned ShowInst
: 1;
100 /// @name Assembler Options
103 unsigned RelaxAll
: 1;
108 AssemblerInvocation() {
110 NoInitialTextSection
= 0;
114 OutputAsmVariant
= 0;
120 static void CreateFromArgs(AssemblerInvocation
&Res
, const char **ArgBegin
,
121 const char **ArgEnd
, Diagnostic
&Diags
);
126 void AssemblerInvocation::CreateFromArgs(AssemblerInvocation
&Opts
,
127 const char **ArgBegin
,
130 using namespace clang::driver::cc1asoptions
;
131 // Parse the arguments.
132 OwningPtr
<OptTable
> OptTbl(createCC1AsOptTable());
133 unsigned MissingArgIndex
, MissingArgCount
;
134 OwningPtr
<InputArgList
> Args(
135 OptTbl
->ParseArgs(ArgBegin
, ArgEnd
,MissingArgIndex
, MissingArgCount
));
137 // Check for missing argument error.
139 Diags
.Report(diag::err_drv_missing_argument
)
140 << Args
->getArgString(MissingArgIndex
) << MissingArgCount
;
142 // Issue errors on unknown arguments.
143 for (arg_iterator it
= Args
->filtered_begin(cc1asoptions::OPT_UNKNOWN
),
144 ie
= Args
->filtered_end(); it
!= ie
; ++it
)
145 Diags
.Report(diag::err_drv_unknown_argument
) << (*it
) ->getAsString(*Args
);
147 // Construct the invocation.
150 Opts
.Triple
= Triple::normalize(Args
->getLastArgValue(OPT_triple
));
151 if (Opts
.Triple
.empty()) // Use the host triple if unspecified.
152 Opts
.Triple
= sys::getHostTriple();
155 Opts
.IncludePaths
= Args
->getAllArgValues(OPT_I
);
156 Opts
.NoInitialTextSection
= Args
->hasArg(OPT_n
);
159 if (Args
->hasArg(OPT_INPUT
)) {
161 for (arg_iterator it
= Args
->filtered_begin(OPT_INPUT
),
162 ie
= Args
->filtered_end(); it
!= ie
; ++it
, First
=false) {
165 Opts
.InputFile
= A
->getValue(*Args
);
167 Diags
.Report(diag::err_drv_unknown_argument
) << A
->getAsString(*Args
);
170 Opts
.LLVMArgs
= Args
->getAllArgValues(OPT_mllvm
);
171 Opts
.OutputPath
= Args
->getLastArgValue(OPT_o
);
172 if (Arg
*A
= Args
->getLastArg(OPT_filetype
)) {
173 StringRef Name
= A
->getValue(*Args
);
174 unsigned OutputType
= StringSwitch
<unsigned>(Name
)
176 .Case("null", FT_Null
)
179 if (OutputType
== ~0U)
180 Diags
.Report(diag::err_drv_invalid_value
)
181 << A
->getAsString(*Args
) << Name
;
183 Opts
.OutputType
= FileType(OutputType
);
185 Opts
.ShowHelp
= Args
->hasArg(OPT_help
);
186 Opts
.ShowVersion
= Args
->hasArg(OPT_version
);
188 // Transliterate Options
189 Opts
.OutputAsmVariant
= Args
->getLastArgIntValue(OPT_output_asm_variant
,
191 Opts
.ShowEncoding
= Args
->hasArg(OPT_show_encoding
);
192 Opts
.ShowInst
= Args
->hasArg(OPT_show_inst
);
195 Opts
.RelaxAll
= Args
->hasArg(OPT_relax_all
);
198 static formatted_raw_ostream
*GetOutputStream(AssemblerInvocation
&Opts
,
201 if (Opts
.OutputPath
.empty())
202 Opts
.OutputPath
= "-";
204 // Make sure that the Out file gets unlinked from the disk if we get a
206 if (Opts
.OutputPath
!= "-")
207 sys::RemoveFileOnSignal(sys::Path(Opts
.OutputPath
));
210 raw_fd_ostream
*Out
=
211 new raw_fd_ostream(Opts
.OutputPath
.c_str(), Error
,
212 (Binary
? raw_fd_ostream::F_Binary
: 0));
213 if (!Error
.empty()) {
214 Diags
.Report(diag::err_fe_unable_to_open_output
)
215 << Opts
.OutputPath
<< Error
;
219 return new formatted_raw_ostream(*Out
, formatted_raw_ostream::DELETE_STREAM
);
222 static bool ExecuteAssembler(AssemblerInvocation
&Opts
, Diagnostic
&Diags
) {
223 // Get the target specific parser.
225 const Target
*TheTarget(TargetRegistry::lookupTarget(Opts
.Triple
, Error
));
227 Diags
.Report(diag::err_target_unknown_triple
) << Opts
.Triple
;
231 OwningPtr
<MemoryBuffer
> BufferPtr
;
232 if (error_code ec
= MemoryBuffer::getFileOrSTDIN(Opts
.InputFile
, BufferPtr
)) {
233 Error
= ec
.message();
234 Diags
.Report(diag::err_fe_error_reading
) << Opts
.InputFile
;
237 MemoryBuffer
*Buffer
= BufferPtr
.take();
241 // Tell SrcMgr about this buffer, which is what the parser will pick up.
242 SrcMgr
.AddNewSourceBuffer(Buffer
, SMLoc());
244 // Record the location of the include directories so that the lexer can find
246 SrcMgr
.setIncludeDirs(Opts
.IncludePaths
);
248 OwningPtr
<MCAsmInfo
> MAI(TheTarget
->createAsmInfo(Opts
.Triple
));
249 assert(MAI
&& "Unable to create target asm info!");
251 bool IsBinary
= Opts
.OutputType
== AssemblerInvocation::FT_Obj
;
252 formatted_raw_ostream
*Out
= GetOutputStream(Opts
, Diags
, IsBinary
);
256 // FIXME: We shouldn't need to do this (and link in codegen).
257 OwningPtr
<TargetMachine
> TM(TheTarget
->createTargetMachine(Opts
.Triple
, ""));
259 Diags
.Report(diag::err_target_unknown_triple
) << Opts
.Triple
;
263 const TargetAsmInfo
*tai
= new TargetAsmInfo(*TM
);
264 MCContext
Ctx(*MAI
, tai
);
266 OwningPtr
<MCStreamer
> Str
;
268 const TargetLoweringObjectFile
&TLOF
=
269 TM
->getTargetLowering()->getObjFileLowering();
270 const_cast<TargetLoweringObjectFile
&>(TLOF
).Initialize(Ctx
, *TM
);
273 if (Opts
.OutputType
== AssemblerInvocation::FT_Asm
) {
275 TheTarget
->createMCInstPrinter(Opts
.OutputAsmVariant
, *MAI
);
276 MCCodeEmitter
*CE
= 0;
277 TargetAsmBackend
*TAB
= 0;
278 if (Opts
.ShowEncoding
) {
279 CE
= TheTarget
->createCodeEmitter(*TM
, Ctx
);
280 TAB
= TheTarget
->createAsmBackend(Opts
.Triple
);
282 Str
.reset(TheTarget
->createAsmStreamer(Ctx
, *Out
, /*asmverbose*/true,
283 /*useLoc*/ true, IP
, CE
, TAB
,
285 } else if (Opts
.OutputType
== AssemblerInvocation::FT_Null
) {
286 Str
.reset(createNullStreamer(Ctx
));
288 assert(Opts
.OutputType
== AssemblerInvocation::FT_Obj
&&
289 "Invalid file type!");
290 MCCodeEmitter
*CE
= TheTarget
->createCodeEmitter(*TM
, Ctx
);
291 TargetAsmBackend
*TAB
= TheTarget
->createAsmBackend(Opts
.Triple
);
292 Str
.reset(TheTarget
->createObjectStreamer(Opts
.Triple
, Ctx
, *TAB
, *Out
,
294 Str
.get()->InitSections();
297 OwningPtr
<MCAsmParser
> Parser(createMCAsmParser(*TheTarget
, SrcMgr
, Ctx
,
299 OwningPtr
<TargetAsmParser
> TAP(TheTarget
->createAsmParser(*Parser
, *TM
));
301 Diags
.Report(diag::err_target_unknown_triple
) << Opts
.Triple
;
305 Parser
->setTargetParser(*TAP
.get());
307 bool Success
= !Parser
->Run(Opts
.NoInitialTextSection
);
312 // Delete output on errors.
313 if (!Success
&& Opts
.OutputPath
!= "-")
314 sys::Path(Opts
.OutputPath
).eraseFromDisk();
319 static void LLVMErrorHandler(void *UserData
, const std::string
&Message
) {
320 Diagnostic
&Diags
= *static_cast<Diagnostic
*>(UserData
);
322 Diags
.Report(diag::err_fe_error_backend
) << Message
;
324 // We cannot recover from llvm errors.
328 int cc1as_main(const char **ArgBegin
, const char **ArgEnd
,
329 const char *Argv0
, void *MainAddr
) {
330 // Print a stack trace if we signal out.
331 sys::PrintStackTraceOnErrorSignal();
332 PrettyStackTraceProgram
X(ArgEnd
- ArgBegin
, ArgBegin
);
333 llvm_shutdown_obj Y
; // Call llvm_shutdown() on exit.
335 // Initialize targets and assembly printers/parsers.
336 InitializeAllTargetInfos();
337 // FIXME: We shouldn't need to initialize the Target(Machine)s.
338 InitializeAllTargets();
339 InitializeAllAsmPrinters();
340 InitializeAllAsmParsers();
342 // Construct our diagnostic client.
343 TextDiagnosticPrinter
*DiagClient
344 = new TextDiagnosticPrinter(errs(), DiagnosticOptions());
345 DiagClient
->setPrefix("clang -cc1as");
346 llvm::IntrusiveRefCntPtr
<DiagnosticIDs
> DiagID(new DiagnosticIDs());
347 Diagnostic
Diags(DiagID
, DiagClient
);
349 // Set an error handler, so that any LLVM backend diagnostics go through our
351 ScopedFatalErrorHandler FatalErrorHandler
352 (LLVMErrorHandler
, static_cast<void*>(&Diags
));
354 // Parse the arguments.
355 AssemblerInvocation Asm
;
356 AssemblerInvocation::CreateFromArgs(Asm
, ArgBegin
, ArgEnd
, Diags
);
360 llvm::OwningPtr
<driver::OptTable
> Opts(driver::createCC1AsOptTable());
361 Opts
->PrintHelp(llvm::outs(), "clang -cc1as", "Clang Integrated Assembler");
367 // FIXME: Use a better -version message?
368 if (Asm
.ShowVersion
) {
369 llvm::cl::PrintVersionMessage();
375 // FIXME: Remove this, one day.
376 if (!Asm
.LLVMArgs
.empty()) {
377 unsigned NumArgs
= Asm
.LLVMArgs
.size();
378 const char **Args
= new const char*[NumArgs
+ 2];
379 Args
[0] = "clang (LLVM option parsing)";
380 for (unsigned i
= 0; i
!= NumArgs
; ++i
)
381 Args
[i
+ 1] = Asm
.LLVMArgs
[i
].c_str();
382 Args
[NumArgs
+ 1] = 0;
383 llvm::cl::ParseCommandLineOptions(NumArgs
+ 1, const_cast<char **>(Args
));
386 // Execute the invocation, unless there were parsing errors.
387 bool Success
= false;
388 if (!Diags
.hasErrorOccurred())
389 Success
= ExecuteAssembler(Asm
, Diags
);
391 // If any timers were active but haven't been destroyed yet, print their
393 TimerGroup::printAll(errs());