1//===- MCLDTargetMachine.cpp ----------------------------------------------===//
2//
3//                     The MCLinker Project
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9#include <mcld/CodeGen/TargetMachine.h>
10
11#include <mcld/Module.h>
12#include <mcld/LinkerConfig.h>
13#include <mcld/CodeGen/MCLinker.h>
14#include <mcld/Support/TargetRegistry.h>
15#include <mcld/Support/ToolOutputFile.h>
16#include <mcld/Target/TargetLDBackend.h>
17
18#include <llvm/Analysis/Passes.h>
19#include <llvm/CodeGen/AsmPrinter.h>
20#include <llvm/CodeGen/MachineFunctionAnalysis.h>
21#include <llvm/CodeGen/MachineModuleInfo.h>
22#include <llvm/CodeGen/GCStrategy.h>
23#include <llvm/CodeGen/Passes.h>
24#include <llvm/IR/DataLayout.h>
25#include <llvm/IR/IRPrintingPasses.h>
26#include <llvm/IR/Verifier.h>
27#include <llvm/MC/MCAsmInfo.h>
28#include <llvm/MC/MCStreamer.h>
29#include <llvm/MC/MCInstrInfo.h>
30#include <llvm/MC/MCSubtargetInfo.h>
31#include <llvm/MC/MCObjectStreamer.h>
32#include <llvm/MC/MCAssembler.h>
33#include <llvm/MC/MCObjectWriter.h>
34#include <llvm/MC/MCContext.h>
35#include <llvm/PassManager.h>
36#include <llvm/Support/CommandLine.h>
37#include <llvm/Support/Debug.h>
38#include <llvm/Support/TargetRegistry.h>
39#include <llvm/Support/FormattedStream.h>
40#include <llvm/Target/TargetInstrInfo.h>
41#include <llvm/Target/TargetLowering.h>
42#include <llvm/Target/TargetOptions.h>
43#include <llvm/Target/TargetSubtargetInfo.h>
44#include <llvm/Target/TargetLoweringObjectFile.h>
45#include <llvm/Target/TargetRegisterInfo.h>
46#include <llvm/Transforms/Scalar.h>
47
48#include <string>
49
50using namespace mcld;
51using namespace llvm;
52
53//===----------------------------------------------------------------------===//
54/// Arguments
55//===----------------------------------------------------------------------===//
56// Enable or disable FastISel. Both options are needed, because
57// FastISel is enabled by default with -fast, and we wish to be
58// able to enable or disable fast-isel independently from -O0.
59static cl::opt<cl::boolOrDefault>
60ArgEnableFastISelOption("lfast-isel", cl::Hidden,
61  cl::desc("Enable the \"fast\" instruction selector"));
62
63static cl::opt<bool>
64ArgShowMCEncoding("lshow-mc-encoding",
65                cl::Hidden,
66                cl::desc("Show encoding in .s output"));
67
68static cl::opt<bool>
69ArgShowMCInst("lshow-mc-inst",
70              cl::Hidden,
71              cl::desc("Show instruction structure in .s output"));
72
73static cl::opt<cl::boolOrDefault>
74ArgAsmVerbose("fverbose-asm",
75              cl::desc("Put extra commentary information in the \
76                       generated assembly code to make it more readable."),
77              cl::init(cl::BOU_UNSET));
78
79static bool getVerboseAsm(TargetMachine &TM) {
80  switch (ArgAsmVerbose) {
81  default:
82  case cl::BOU_UNSET: return TM.getAsmVerbosityDefault();
83  case cl::BOU_TRUE:  return true;
84  case cl::BOU_FALSE: return false;
85  }
86}
87
88
89//===----------------------------------------------------------------------===//
90// MCLDTargetMachine
91//===----------------------------------------------------------------------===//
92mcld::MCLDTargetMachine::MCLDTargetMachine(llvm::TargetMachine &pTM,
93                                           const llvm::Target& pLLVMTarget,
94                                           const mcld::Target& pMCLDTarget,
95                                           const std::string& pTriple)
96  : m_TM(pTM),
97    m_pLLVMTarget(&pLLVMTarget),
98    m_pMCLDTarget(&pMCLDTarget),
99    m_Triple(pTriple) {
100}
101
102mcld::MCLDTargetMachine::~MCLDTargetMachine()
103{
104  m_pLLVMTarget = NULL;
105  m_pMCLDTarget = NULL;
106}
107
108const mcld::Target& mcld::MCLDTargetMachine::getTarget() const
109{
110  return *m_pMCLDTarget;
111}
112
113/// Turn exception handling constructs into something the code generators can
114/// handle.
115static void addPassesToHandleExceptions(llvm::TargetMachine *TM,
116                                        llvm::legacy::PassManagerBase &PM) {
117  switch (TM->getMCAsmInfo()->getExceptionHandlingType()) {
118  case llvm::ExceptionHandling::SjLj:
119    // SjLj piggy-backs on dwarf for this bit. The cleanups done apply to both
120    // Dwarf EH prepare needs to be run after SjLj prepare. Otherwise,
121    // catch info can get misplaced when a selector ends up more than one block
122    // removed from the parent invoke(s). This could happen when a landing
123    // pad is shared by multiple invokes and is also a target of a normal
124    // edge from elsewhere.
125    PM.add(createSjLjEHPreparePass(TM));
126    // FALLTHROUGH
127  case llvm::ExceptionHandling::DwarfCFI:
128  case llvm::ExceptionHandling::ARM:
129  case llvm::ExceptionHandling::WinEH:
130    PM.add(createDwarfEHPass(TM));
131    break;
132  case llvm::ExceptionHandling::None:
133    PM.add(createLowerInvokePass());
134
135    // The lower invoke pass may create unreachable code. Remove it.
136    PM.add(createUnreachableBlockEliminationPass());
137    break;
138  }
139}
140
141
142static llvm::MCContext *
143addPassesToGenerateCode(llvm::LLVMTargetMachine *TM,
144                        llvm::legacy::PassManagerBase &PM,
145                        bool DisableVerify)
146{
147  // Targets may override createPassConfig to provide a target-specific sublass.
148  TargetPassConfig *PassConfig = TM->createPassConfig(PM);
149
150  // Set PassConfig options provided by TargetMachine.
151  PassConfig->setDisableVerify(DisableVerify);
152
153  PM.add(PassConfig);
154
155  PassConfig->addIRPasses();
156
157  addPassesToHandleExceptions(TM, PM);
158
159  PassConfig->addISelPrepare();
160
161  // Install a MachineModuleInfo class, which is an immutable pass that holds
162  // all the per-module stuff we're generating, including MCContext.
163  MachineModuleInfo *MMI =
164    new MachineModuleInfo(*TM->getMCAsmInfo(), *TM->getRegisterInfo(),
165                          &TM->getTargetLowering()->getObjFileLowering());
166  PM.add(MMI);
167  MCContext *Context = &MMI->getContext(); // Return the MCContext by-ref.
168
169  // Set up a MachineFunction for the rest of CodeGen to work on.
170  PM.add(new MachineFunctionAnalysis(*TM));
171
172  // Enable FastISel with -fast, but allow that to be overridden.
173  if (ArgEnableFastISelOption == cl::BOU_TRUE ||
174      (TM->getOptLevel() == CodeGenOpt::None &&
175       ArgEnableFastISelOption != cl::BOU_FALSE))
176    TM->setFastISel(true);
177
178  // Ask the target for an isel.
179  if (PassConfig->addInstSelector())
180    return NULL;
181
182  PassConfig->addMachinePasses();
183
184  PassConfig->setInitialized();
185
186  return Context;
187
188}
189
190bool
191mcld::MCLDTargetMachine::addPassesToEmitFile(llvm::legacy::PassManagerBase &pPM,
192                                             mcld::ToolOutputFile& pOutput,
193                                             mcld::CodeGenFileType pFileType,
194                                             CodeGenOpt::Level pOptLvl,
195                                             mcld::Module& pModule,
196                                             LinkerConfig& pConfig,
197                                             bool pDisableVerify)
198{
199
200  llvm::MCContext* Context =
201          addPassesToGenerateCode(static_cast<llvm::LLVMTargetMachine*>(&m_TM),
202                                  pPM, pDisableVerify);
203  if (!Context)
204    return true;
205
206  switch(pFileType) {
207  default:
208  case mcld::CGFT_NULLFile:
209    assert(0 && "fatal: file type is not set!");
210    break;
211  case CGFT_ASMFile: {
212    assert(Context != 0 && "Failed to get MCContext");
213
214    if (getTM().Options.MCOptions.MCSaveTempLabels)
215      Context->setAllowTemporaryLabels(false);
216
217    if (addCompilerPasses(pPM,
218                          pOutput.formatted_os(),
219                          Context))
220      return true;
221    break;
222  }
223  case CGFT_OBJFile: {
224    assert(Context != 0 && "Failed to get MCContext");
225
226    if (getTM().Options.MCOptions.MCSaveTempLabels)
227      Context->setAllowTemporaryLabels(false);
228    if (addAssemblerPasses(pPM,
229                           pOutput.formatted_os(),
230                           Context))
231      return true;
232    break;
233  }
234  case CGFT_EXEFile: {
235    pConfig.setCodeGenType(LinkerConfig::Exec);
236    if (addLinkerPasses(pPM,
237                        pConfig,
238                        pModule,
239                        pOutput.fd(),
240                        Context))
241      return true;
242    break;
243  }
244  case CGFT_BINARY: {
245    pConfig.setCodeGenType(LinkerConfig::Binary);
246    if (addLinkerPasses(pPM,
247                        pConfig,
248                        pModule,
249                        pOutput.fd(),
250                        Context))
251      return true;
252    break;
253  }
254  case CGFT_DSOFile: {
255    pConfig.setCodeGenType(LinkerConfig::DynObj);
256    if (addLinkerPasses(pPM,
257                        pConfig,
258                        pModule,
259                        pOutput.fd(),
260                        Context))
261      return true;
262    break;
263  }
264  case CGFT_PARTIAL: {
265    pConfig.setCodeGenType(LinkerConfig::Object);
266    if (addLinkerPasses(pPM,
267                        pConfig,
268                        pModule,
269                        pOutput.fd(),
270                        Context))
271      return true;
272    break;
273  }
274  } // switch
275  return false;
276}
277
278bool
279mcld::MCLDTargetMachine::addCompilerPasses(llvm::legacy::PassManagerBase &pPM,
280                                           llvm::formatted_raw_ostream &pOutput,
281                                           llvm::MCContext *&Context)
282{
283  const MCAsmInfo &MAI = *getTM().getMCAsmInfo();
284  const MCInstrInfo &MII = *getTM().getInstrInfo();
285  const MCRegisterInfo &MRI = *getTM().getRegisterInfo();
286  const MCSubtargetInfo &STI = getTM().getSubtarget<MCSubtargetInfo>();
287
288  MCInstPrinter *InstPrinter =
289    m_pLLVMTarget->createMCInstPrinter(MAI.getAssemblerDialect(), MAI,
290                                       MII, *Context->getRegisterInfo(), STI);
291
292  MCCodeEmitter* MCE = 0;
293  MCAsmBackend *MAB = 0;
294  if (ArgShowMCEncoding) {
295    MCE = m_pLLVMTarget->createMCCodeEmitter(MII, MRI, STI, *Context);
296    MAB = m_pLLVMTarget->createMCAsmBackend(MRI, m_Triple,
297                                            getTM().getTargetCPU());
298  }
299
300
301  // now, we have MCCodeEmitter and MCAsmBackend, we can create AsmStreamer.
302  std::unique_ptr<MCStreamer> AsmStreamer(
303    m_pLLVMTarget->createAsmStreamer(*Context, pOutput,
304                                     getVerboseAsm(getTM()),
305                                     getTM().Options.MCOptions.MCUseDwarfDirectory,
306                                     InstPrinter,
307                                     MCE, MAB,
308                                     ArgShowMCInst));
309
310  llvm::MachineFunctionPass* funcPass =
311    m_pLLVMTarget->createAsmPrinter(getTM(), *AsmStreamer.get());
312
313  if (funcPass == 0)
314    return true;
315  // If successful, createAsmPrinter took ownership of AsmStreamer
316  AsmStreamer.release();
317  pPM.add(funcPass);
318  return false;
319}
320
321bool
322mcld::MCLDTargetMachine::addAssemblerPasses(llvm::legacy::PassManagerBase &pPM,
323                                            llvm::raw_ostream &pOutput,
324                                            llvm::MCContext *&Context)
325{
326  // MCCodeEmitter
327  const MCInstrInfo &MII = *getTM().getInstrInfo();
328  const MCRegisterInfo &MRI = *getTM().getRegisterInfo();
329  const MCSubtargetInfo &STI = getTM().getSubtarget<MCSubtargetInfo>();
330  MCCodeEmitter* MCE =
331    m_pLLVMTarget->createMCCodeEmitter(MII, MRI, STI, *Context);
332
333  // MCAsmBackend
334  MCAsmBackend* MAB =
335    m_pLLVMTarget->createMCAsmBackend(MRI, m_Triple, getTM().getTargetCPU());
336  if (MCE == 0 || MAB == 0)
337    return true;
338
339  // now, we have MCCodeEmitter and MCAsmBackend, we can create AsmStreamer.
340  std::unique_ptr<MCStreamer> AsmStreamer(m_pLLVMTarget->createMCObjectStreamer(
341    m_Triple, *Context, *MAB, pOutput, MCE, STI,
342    getTM().Options.MCOptions.MCRelaxAll, getTM().Options.MCOptions.MCNoExecStack));
343
344  AsmStreamer.get()->InitSections();
345  MachineFunctionPass *funcPass =
346    m_pLLVMTarget->createAsmPrinter(getTM(), *AsmStreamer.get());
347  if (funcPass == 0)
348    return true;
349  // If successful, createAsmPrinter took ownership of AsmStreamer
350  AsmStreamer.release();
351  pPM.add(funcPass);
352  return false;
353}
354
355bool
356mcld::MCLDTargetMachine::addLinkerPasses(llvm::legacy::PassManagerBase &pPM,
357                                         LinkerConfig& pConfig,
358                                         mcld::Module& pModule,
359                                         mcld::FileHandle& pFileHandle,
360                                         llvm::MCContext *&Context)
361{
362  // set up output's SOName
363  if (pConfig.options().soname().empty()) {
364    // if the output is a shared object, and the option -soname was not
365    // enable, set soname as the output file name. soname must be UTF-8 string.
366    pConfig.options().setSOName(pFileHandle.path().filename().native());
367  }
368
369  // set up output module name
370  pModule.setName(pFileHandle.path().filename().native());
371
372  MachineFunctionPass* funcPass = m_pMCLDTarget->createMCLinker(m_Triple,
373                                                                pConfig,
374                                                                pModule,
375                                                                pFileHandle);
376  if (NULL == funcPass)
377    return true;
378
379  pPM.add(funcPass);
380  return false;
381}
382
383