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