diff options
| author | Ed Schouten <ed@FreeBSD.org> | 2009-06-02 17:58:47 +0000 | 
|---|---|---|
| committer | Ed Schouten <ed@FreeBSD.org> | 2009-06-02 17:58:47 +0000 | 
| commit | ec2b103c267a06a66e926f62cd96767b280f5cf5 (patch) | |
| tree | ce7d964cbb5e39695b71481698f10cb099c23d4a /lib/Basic/TargetInfo.cpp | |
Notes
Diffstat (limited to 'lib/Basic/TargetInfo.cpp')
| -rw-r--r-- | lib/Basic/TargetInfo.cpp | 295 | 
1 files changed, 295 insertions, 0 deletions
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp new file mode 100644 index 000000000000..1e8ca2bd56c4 --- /dev/null +++ b/lib/Basic/TargetInfo.cpp @@ -0,0 +1,295 @@ +//===--- TargetInfo.cpp - Information about Target machine ----------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +//  This file implements the TargetInfo and TargetInfoImpl interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/STLExtras.h" +#include <cstdlib> +using namespace clang; + +// TargetInfo Constructor. +TargetInfo::TargetInfo(const std::string &T) : Triple(T) { +  // Set defaults.  Defaults are set for a 32-bit RISC platform, +  // like PPC or SPARC. +  // These should be overridden by concrete targets as needed. +  CharIsSigned = true; +  TLSSupported = true; +  PointerWidth = PointerAlign = 32; +  WCharWidth = WCharAlign = 32; +  IntWidth = IntAlign = 32; +  LongWidth = LongAlign = 32; +  LongLongWidth = LongLongAlign = 64; +  FloatWidth = 32; +  FloatAlign = 32; +  DoubleWidth = 64; +  DoubleAlign = 64; +  LongDoubleWidth = 64; +  LongDoubleAlign = 64; +  IntMaxTWidth = 64; +  SizeType = UnsignedLong; +  PtrDiffType = SignedLong; +  IntMaxType = SignedLongLong; +  UIntMaxType = UnsignedLongLong; +  IntPtrType = SignedLong; +  WCharType = SignedInt; +  FloatFormat = &llvm::APFloat::IEEEsingle; +  DoubleFormat = &llvm::APFloat::IEEEdouble; +  LongDoubleFormat = &llvm::APFloat::IEEEdouble; +  DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" +                      "i64:64:64-f32:32:32-f64:64:64"; +  UserLabelPrefix = "_"; +} + +// Out of line virtual dtor for TargetInfo. +TargetInfo::~TargetInfo() {} + +/// getTypeName - Return the user string for the specified integer type enum. +/// For example, SignedShort -> "short". +const char *TargetInfo::getTypeName(IntType T) { +  switch (T) { +  default: assert(0 && "not an integer!"); +  case SignedShort:      return "short"; +  case UnsignedShort:    return "unsigned short"; +  case SignedInt:        return "int"; +  case UnsignedInt:      return "unsigned int"; +  case SignedLong:       return "long int"; +  case UnsignedLong:     return "long unsigned int"; +  case SignedLongLong:   return "long long int"; +  case UnsignedLongLong: return "long long unsigned int"; +  } +} + +//===----------------------------------------------------------------------===// + + +static void removeGCCRegisterPrefix(const char *&Name) { +  if (Name[0] == '%' || Name[0] == '#') +    Name++; +} + +/// isValidGCCRegisterName - Returns whether the passed in string +/// is a valid register name according to GCC. This is used by Sema for +/// inline asm statements. +bool TargetInfo::isValidGCCRegisterName(const char *Name) const { +  const char * const *Names; +  unsigned NumNames; +   +  // Get rid of any register prefix. +  removeGCCRegisterPrefix(Name); + +   +  if (strcmp(Name, "memory") == 0 || +      strcmp(Name, "cc") == 0) +    return true; +   +  getGCCRegNames(Names, NumNames); +   +  // If we have a number it maps to an entry in the register name array. +  if (isdigit(Name[0])) { +    char *End; +    int n = (int)strtol(Name, &End, 0); +    if (*End == 0) +      return n >= 0 && (unsigned)n < NumNames; +  } + +  // Check register names. +  for (unsigned i = 0; i < NumNames; i++) { +    if (strcmp(Name, Names[i]) == 0) +      return true; +  } +   +  // Now check aliases. +  const GCCRegAlias *Aliases; +  unsigned NumAliases; +   +  getGCCRegAliases(Aliases, NumAliases); +  for (unsigned i = 0; i < NumAliases; i++) { +    for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) { +      if (!Aliases[i].Aliases[j]) +        break; +      if (strcmp(Aliases[i].Aliases[j], Name) == 0) +        return true; +    } +  } +   +  return false; +} + +const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const { +  assert(isValidGCCRegisterName(Name) && "Invalid register passed in"); +   +  removeGCCRegisterPrefix(Name); +     +  const char * const *Names; +  unsigned NumNames; + +  getGCCRegNames(Names, NumNames); + +  // First, check if we have a number. +  if (isdigit(Name[0])) { +    char *End; +    int n = (int)strtol(Name, &End, 0); +    if (*End == 0) { +      assert(n >= 0 && (unsigned)n < NumNames &&  +             "Out of bounds register number!"); +      return Names[n]; +    } +  } +   +  // Now check aliases. +  const GCCRegAlias *Aliases; +  unsigned NumAliases; +   +  getGCCRegAliases(Aliases, NumAliases); +  for (unsigned i = 0; i < NumAliases; i++) { +    for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) { +      if (!Aliases[i].Aliases[j]) +        break; +      if (strcmp(Aliases[i].Aliases[j], Name) == 0) +        return Aliases[i].Register; +    } +  } +   +  return Name; +} + +bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const { +  const char *Name = Info.getConstraintStr().c_str(); +  // An output constraint must start with '=' or '+' +  if (*Name != '=' && *Name != '+') +    return false; + +  if (*Name == '+') +    Info.setIsReadWrite(); + +  Name++; +  while (*Name) { +    switch (*Name) { +    default: +      if (!validateAsmConstraint(Name, Info)) { +        // FIXME: We temporarily return false +        // so we can add more constraints as we hit it. +        // Eventually, an unknown constraint should just be treated as 'g'. +        return false; +      } +    case '&': // early clobber. +      break; +    case 'r': // general register. +      Info.setAllowsRegister(); +      break; +    case 'm': // memory operand. +      Info.setAllowsMemory(); +      break; +    case 'g': // general register, memory operand or immediate integer. +    case 'X': // any operand. +      Info.setAllowsRegister(); +      Info.setAllowsMemory(); +      break; +    } +     +    Name++; +  } +   +  return true; +} + +bool TargetInfo::resolveSymbolicName(const char *&Name, +                                     ConstraintInfo *OutputConstraints, +                                     unsigned NumOutputs, +                                     unsigned &Index) const { +  assert(*Name == '[' && "Symbolic name did not start with '['"); +  Name++; +  const char *Start = Name; +  while (*Name && *Name != ']') +    Name++; +   +  if (!*Name) { +    // Missing ']' +    return false; +  } +   +  std::string SymbolicName(Start, Name - Start); +   +  for (Index = 0; Index != NumOutputs; ++Index) +    if (SymbolicName == OutputConstraints[Index].getName()) +      return true; + +  return false; +} + +bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints, +                                         unsigned NumOutputs, +                                         ConstraintInfo &Info) const { +  const char *Name = Info.ConstraintStr.c_str(); + +  while (*Name) { +    switch (*Name) { +    default: +      // Check if we have a matching constraint +      if (*Name >= '0' && *Name <= '9') { +        unsigned i = *Name - '0'; +   +        // Check if matching constraint is out of bounds. +        if (i >= NumOutputs) +          return false; +         +        // The constraint should have the same info as the respective  +        // output constraint. +        Info.setTiedOperand(i, OutputConstraints[i]); +      } else if (!validateAsmConstraint(Name, Info)) { +        // FIXME: This error return is in place temporarily so we can +        // add more constraints as we hit it.  Eventually, an unknown +        // constraint should just be treated as 'g'. +        return false; +      } +      break; +    case '[': { +      unsigned Index = 0; +      if (!resolveSymbolicName(Name, OutputConstraints, NumOutputs, Index)) +        return false; +     +      break; +    }           +    case '%': // commutative +      // FIXME: Fail if % is used with the last operand. +      break; +    case 'i': // immediate integer. +    case 'n': // immediate integer with a known value. +      break; +    case 'I':  // Various constant constraints with target-specific meanings. +    case 'J': +    case 'K': +    case 'L': +    case 'M': +    case 'N': +    case 'O': +    case 'P': +      break; +    case 'r': // general register. +      Info.setAllowsRegister(); +      break; +    case 'm': // memory operand. +      Info.setAllowsMemory(); +      break; +    case 'g': // general register, memory operand or immediate integer. +    case 'X': // any operand. +      Info.setAllowsRegister(); +      Info.setAllowsMemory(); +      break; +    } +     +    Name++; +  } +   +  return true; +}  | 
