1//===- TargetRegistry.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/Support/TargetRegistry.h>
10
11using namespace mcld;
12
13TargetRegistry::TargetListTy mcld::TargetRegistry::s_TargetList;
14
15//===----------------------------------------------------------------------===//
16// TargetRegistry
17//===----------------------------------------------------------------------===//
18void TargetRegistry::RegisterTarget(Target& pTarget,
19                                    const char* pName,
20                                    Target::TripleMatchQualityFnTy pQualityFn)
21{
22  pTarget.Name = pName;
23  pTarget.TripleMatchQualityFn = pQualityFn;
24
25  s_TargetList.push_back(&pTarget);
26}
27
28const Target* TargetRegistry::lookupTarget(const std::string &pTriple,
29                                           std::string &pError)
30{
31  if (empty()) {
32    pError = "Unable to find target for this triple (no target are registered)";
33    return NULL;
34  }
35
36  llvm::Triple triple(pTriple);
37  Target* best = NULL, *ambiguity = NULL;
38  unsigned int highest = 0;
39
40  for (iterator target = begin(), ie = end(); target != ie; ++target) {
41    unsigned int quality = (*target)->getTripleQuality(triple);
42    if (quality > 0) {
43      if (NULL == best || highest < quality) {
44        highest = quality;
45        best = *target;
46        ambiguity = NULL;
47      }
48      else if (highest == quality) {
49        ambiguity = *target;
50      }
51    }
52  }
53
54  if (NULL == best) {
55    pError = "No availaible targets are compatible with this triple.";
56    return NULL;
57  }
58
59  if (NULL != ambiguity) {
60    pError = std::string("Ambiguous targets: \"") +
61             best->name() + "\" and \"" + ambiguity->name() + "\"";
62    return NULL;
63  }
64
65  return best;
66}
67
68const Target* TargetRegistry::lookupTarget(const std::string& pArchName,
69                                           llvm::Triple& pTriple,
70                                           std::string& pError)
71{
72  const Target* result = NULL;
73  if (!pArchName.empty()) {
74    for (mcld::TargetRegistry::iterator it = mcld::TargetRegistry::begin(),
75           ie = mcld::TargetRegistry::end(); it != ie; ++it) {
76      if (pArchName == (*it)->name()) {
77        result = *it;
78        break;
79      }
80    }
81
82    if (NULL == result) {
83      pError = std::string("invalid target '") + pArchName + "'.\n";
84      return NULL;
85    }
86
87    // Adjust the triple to match (if known), otherwise stick with the
88    // module/host triple.
89    llvm::Triple::ArchType type =
90                               llvm::Triple::getArchTypeForLLVMName(pArchName);
91    if (llvm::Triple::UnknownArch != type)
92      pTriple.setArch(type);
93  }
94  else {
95    std::string error;
96    result = lookupTarget(pTriple.getTriple(), error);
97    if (NULL == result) {
98      pError = std::string("unable to get target for `") +
99               pTriple.getTriple() + "'\n" +
100               "(Detail: " + error + ")\n";
101      return NULL;
102    }
103  }
104  return result;
105}
106