| //===--- 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. | 
 |   TLSSupported = true; | 
 |   PointerWidth = PointerAlign = 32; | 
 |   WCharWidth = WCharAlign = 32; | 
 |   Char16Width = Char16Align = 16; | 
 |   Char32Width = Char32Align = 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; | 
 |   Char16Type = UnsignedShort; | 
 |   Char32Type = UnsignedInt; | 
 |   Int64Type = SignedLongLong; | 
 |   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; | 
 | } |