Home | History | Annotate | Download | only in Target
      1 //===-------------------------- TargetRecip.cpp ---------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This class is used to customize machine-specific reciprocal estimate code
     11 // generation in a target-independent way.
     12 // If a target does not support operations in this specification, then code
     13 // generation will default to using supported operations.
     14 //
     15 //===----------------------------------------------------------------------===//
     16 
     17 #include "llvm/Target/TargetRecip.h"
     18 #include "llvm/ADT/STLExtras.h"
     19 #include "llvm/ADT/StringRef.h"
     20 #include "llvm/Support/ErrorHandling.h"
     21 
     22 using namespace llvm;
     23 
     24 // These are the names of the individual reciprocal operations. These are
     25 // the key strings for queries and command-line inputs.
     26 // In addition, the command-line interface recognizes the global parameters
     27 // "all", "none", and "default".
     28 static const char *const RecipOps[] = {
     29   "divd",
     30   "divf",
     31   "vec-divd",
     32   "vec-divf",
     33   "sqrtd",
     34   "sqrtf",
     35   "vec-sqrtd",
     36   "vec-sqrtf",
     37 };
     38 
     39 // The uninitialized state is needed for the enabled settings and refinement
     40 // steps because custom settings may arrive via the command-line before target
     41 // defaults are set.
     42 TargetRecip::TargetRecip() {
     43   unsigned NumStrings = llvm::array_lengthof(RecipOps);
     44   for (unsigned i = 0; i < NumStrings; ++i)
     45     RecipMap.insert(std::make_pair(RecipOps[i], RecipParams()));
     46 }
     47 
     48 static bool parseRefinementStep(StringRef In, size_t &Position,
     49                                 uint8_t &Value) {
     50   const char RefStepToken = ':';
     51   Position = In.find(RefStepToken);
     52   if (Position == StringRef::npos)
     53     return false;
     54 
     55   StringRef RefStepString = In.substr(Position + 1);
     56   // Allow exactly one numeric character for the additional refinement
     57   // step parameter.
     58   if (RefStepString.size() == 1) {
     59     char RefStepChar = RefStepString[0];
     60     if (RefStepChar >= '0' && RefStepChar <= '9') {
     61       Value = RefStepChar - '0';
     62       return true;
     63     }
     64   }
     65   report_fatal_error("Invalid refinement step for -recip.");
     66 }
     67 
     68 bool TargetRecip::parseGlobalParams(const std::string &Arg) {
     69   StringRef ArgSub = Arg;
     70 
     71   // Look for an optional setting of the number of refinement steps needed
     72   // for this type of reciprocal operation.
     73   size_t RefPos;
     74   uint8_t RefSteps;
     75   StringRef RefStepString;
     76   if (parseRefinementStep(ArgSub, RefPos, RefSteps)) {
     77     // Split the string for further processing.
     78     RefStepString = ArgSub.substr(RefPos + 1);
     79     ArgSub = ArgSub.substr(0, RefPos);
     80   }
     81   bool Enable;
     82   bool UseDefaults;
     83   if (ArgSub == "all") {
     84     UseDefaults = false;
     85     Enable = true;
     86   } else if (ArgSub == "none") {
     87     UseDefaults = false;
     88     Enable = false;
     89   } else if (ArgSub == "default") {
     90     UseDefaults = true;
     91   } else {
     92     // Any other string is invalid or an individual setting.
     93     return false;
     94   }
     95 
     96   // All enable values will be initialized to target defaults if 'default' was
     97   // specified.
     98   if (!UseDefaults)
     99     for (auto &KV : RecipMap)
    100       KV.second.Enabled = Enable;
    101 
    102   // Custom refinement count was specified with all, none, or default.
    103   if (!RefStepString.empty())
    104     for (auto &KV : RecipMap)
    105       KV.second.RefinementSteps = RefSteps;
    106 
    107   return true;
    108 }
    109 
    110 void TargetRecip::parseIndividualParams(const std::vector<std::string> &Args) {
    111   static const char DisabledPrefix = '!';
    112   unsigned NumArgs = Args.size();
    113 
    114   for (unsigned i = 0; i != NumArgs; ++i) {
    115     StringRef Val = Args[i];
    116 
    117     bool IsDisabled = Val[0] == DisabledPrefix;
    118     // Ignore the disablement token for string matching.
    119     if (IsDisabled)
    120       Val = Val.substr(1);
    121 
    122     size_t RefPos;
    123     uint8_t RefSteps;
    124     StringRef RefStepString;
    125     if (parseRefinementStep(Val, RefPos, RefSteps)) {
    126       // Split the string for further processing.
    127       RefStepString = Val.substr(RefPos + 1);
    128       Val = Val.substr(0, RefPos);
    129     }
    130 
    131     RecipIter Iter = RecipMap.find(Val);
    132     if (Iter == RecipMap.end()) {
    133       // Try again specifying float suffix.
    134       Iter = RecipMap.find(Val.str() + 'f');
    135       if (Iter == RecipMap.end()) {
    136         Iter = RecipMap.find(Val.str() + 'd');
    137         assert(Iter == RecipMap.end() && "Float entry missing from map");
    138         report_fatal_error("Invalid option for -recip.");
    139       }
    140 
    141       // The option was specified without a float or double suffix.
    142       if (RecipMap[Val.str() + 'd'].Enabled != Uninitialized) {
    143         // Make sure that the double entry was not already specified.
    144         // The float entry will be checked below.
    145         report_fatal_error("Duplicate option for -recip.");
    146       }
    147     }
    148 
    149     if (Iter->second.Enabled != Uninitialized)
    150       report_fatal_error("Duplicate option for -recip.");
    151 
    152     // Mark the matched option as found. Do not allow duplicate specifiers.
    153     Iter->second.Enabled = !IsDisabled;
    154     if (!RefStepString.empty())
    155       Iter->second.RefinementSteps = RefSteps;
    156 
    157     // If the precision was not specified, the double entry is also initialized.
    158     if (Val.back() != 'f' && Val.back() != 'd') {
    159       RecipParams &Params = RecipMap[Val.str() + 'd'];
    160       Params.Enabled = !IsDisabled;
    161       if (!RefStepString.empty())
    162         Params.RefinementSteps = RefSteps;
    163     }
    164   }
    165 }
    166 
    167 TargetRecip::TargetRecip(const std::vector<std::string> &Args) :
    168   TargetRecip() {
    169   unsigned NumArgs = Args.size();
    170 
    171   // Check if "all", "default", or "none" was specified.
    172   if (NumArgs == 1 && parseGlobalParams(Args[0]))
    173     return;
    174 
    175   parseIndividualParams(Args);
    176 }
    177 
    178 bool TargetRecip::isEnabled(StringRef Key) const {
    179   ConstRecipIter Iter = RecipMap.find(Key);
    180   assert(Iter != RecipMap.end() && "Unknown name for reciprocal map");
    181   assert(Iter->second.Enabled != Uninitialized &&
    182          "Enablement setting was not initialized");
    183   return Iter->second.Enabled;
    184 }
    185 
    186 unsigned TargetRecip::getRefinementSteps(StringRef Key) const {
    187   ConstRecipIter Iter = RecipMap.find(Key);
    188   assert(Iter != RecipMap.end() && "Unknown name for reciprocal map");
    189   assert(Iter->second.RefinementSteps != Uninitialized &&
    190          "Refinement step setting was not initialized");
    191   return Iter->second.RefinementSteps;
    192 }
    193 
    194 /// Custom settings (previously initialized values) override target defaults.
    195 void TargetRecip::setDefaults(StringRef Key, bool Enable,
    196                               unsigned RefSteps) {
    197   if (Key == "all") {
    198     for (auto &KV : RecipMap) {
    199       RecipParams &RP = KV.second;
    200       if (RP.Enabled == Uninitialized)
    201         RP.Enabled = Enable;
    202       if (RP.RefinementSteps == Uninitialized)
    203         RP.RefinementSteps = RefSteps;
    204     }
    205   } else {
    206     RecipParams &RP = RecipMap[Key];
    207     if (RP.Enabled == Uninitialized)
    208       RP.Enabled = Enable;
    209     if (RP.RefinementSteps == Uninitialized)
    210       RP.RefinementSteps = RefSteps;
    211   }
    212 }
    213 
    214 bool TargetRecip::operator==(const TargetRecip &Other) const {
    215   for (const auto &KV : RecipMap) {
    216     StringRef Op = KV.first;
    217     const RecipParams &RP = KV.second;
    218     const RecipParams &OtherRP = Other.RecipMap.find(Op)->second;
    219     if (RP.RefinementSteps != OtherRP.RefinementSteps)
    220       return false;
    221     if (RP.Enabled != OtherRP.Enabled)
    222       return false;
    223   }
    224   return true;
    225 }
    226