| //===- TargetRegistry.cpp -------------------------------------------------===// |
| // |
| // The MCLinker Project |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| #include "mcld/Support/TargetRegistry.h" |
| |
| namespace mcld { |
| |
| TargetRegistry::TargetListTy mcld::TargetRegistry::s_TargetList; |
| |
| //===----------------------------------------------------------------------===// |
| // TargetRegistry |
| //===----------------------------------------------------------------------===// |
| void TargetRegistry::RegisterTarget(Target& pTarget, |
| const char* pName, |
| Target::TripleMatchQualityFnTy pQualityFn) { |
| pTarget.Name = pName; |
| pTarget.TripleMatchQualityFn = pQualityFn; |
| |
| s_TargetList.push_back(&pTarget); |
| } |
| |
| const Target* TargetRegistry::lookupTarget(const std::string& pTriple, |
| std::string& pError) { |
| if (empty()) { |
| pError = "Unable to find target for this triple (no target are registered)"; |
| return NULL; |
| } |
| |
| llvm::Triple triple(pTriple); |
| Target* best = NULL, * ambiguity = NULL; |
| unsigned int highest = 0; |
| |
| for (iterator target = begin(), ie = end(); target != ie; ++target) { |
| unsigned int quality = (*target)->getTripleQuality(triple); |
| if (quality > 0) { |
| if (best == NULL || highest < quality) { |
| highest = quality; |
| best = *target; |
| ambiguity = NULL; |
| } else if (highest == quality) { |
| ambiguity = *target; |
| } |
| } |
| } |
| |
| if (best == NULL) { |
| pError = "No availaible targets are compatible with this triple."; |
| return NULL; |
| } |
| |
| if (NULL != ambiguity) { |
| pError = std::string("Ambiguous targets: \"") + best->name() + "\" and \"" + |
| ambiguity->name() + "\""; |
| return NULL; |
| } |
| |
| return best; |
| } |
| |
| const Target* TargetRegistry::lookupTarget(const std::string& pArchName, |
| llvm::Triple& pTriple, |
| std::string& pError) { |
| const Target* result = NULL; |
| if (!pArchName.empty()) { |
| for (mcld::TargetRegistry::iterator it = mcld::TargetRegistry::begin(), |
| ie = mcld::TargetRegistry::end(); |
| it != ie; |
| ++it) { |
| if (pArchName == (*it)->name()) { |
| result = *it; |
| break; |
| } |
| } |
| |
| if (result == NULL) { |
| pError = std::string("invalid target '") + pArchName + "'.\n"; |
| return NULL; |
| } |
| |
| // Adjust the triple to match (if known), otherwise stick with the |
| // module/host triple. |
| llvm::Triple::ArchType type = |
| llvm::Triple::getArchTypeForLLVMName(pArchName); |
| if (llvm::Triple::UnknownArch != type) |
| pTriple.setArch(type); |
| } else { |
| std::string error; |
| result = lookupTarget(pTriple.getTriple(), error); |
| if (result == NULL) { |
| pError = std::string("unable to get target for `") + pTriple.getTriple() + |
| "'\n" + "(Detail: " + error + ")\n"; |
| return NULL; |
| } |
| } |
| return result; |
| } |
| |
| } // namespace mcld |