blob: afffc5c468050a7fcf11675e2f86e8229fd2b98e [file] [log] [blame]
//===- 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>
using 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 (NULL == best || highest < quality) {
highest = quality;
best = *target;
ambiguity = NULL;
}
else if (highest == quality) {
ambiguity = *target;
}
}
}
if (NULL == best) {
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 (NULL == result) {
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 (NULL == result) {
pError = std::string("unable to get target for `") +
pTriple.getTriple() + "'\n" +
"(Detail: " + error + ")\n";
return NULL;
}
}
return result;
}