| //===-------------------------- TargetRecip.cpp ---------------------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This class is used to customize machine-specific reciprocal estimate code |
| // generation in a target-independent way. |
| // If a target does not support operations in this specification, then code |
| // generation will default to using supported operations. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/Target/TargetRecip.h" |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/Support/ErrorHandling.h" |
| |
| using namespace llvm; |
| |
| // These are the names of the individual reciprocal operations. These are |
| // the key strings for queries and command-line inputs. |
| // In addition, the command-line interface recognizes the global parameters |
| // "all", "none", and "default". |
| static const char *const RecipOps[] = { |
| "divd", |
| "divf", |
| "vec-divd", |
| "vec-divf", |
| "sqrtd", |
| "sqrtf", |
| "vec-sqrtd", |
| "vec-sqrtf", |
| }; |
| |
| // The uninitialized state is needed for the enabled settings and refinement |
| // steps because custom settings may arrive via the command-line before target |
| // defaults are set. |
| TargetRecip::TargetRecip() { |
| unsigned NumStrings = llvm::array_lengthof(RecipOps); |
| for (unsigned i = 0; i < NumStrings; ++i) |
| RecipMap.insert(std::make_pair(RecipOps[i], RecipParams())); |
| } |
| |
| static bool parseRefinementStep(StringRef In, size_t &Position, |
| uint8_t &Value) { |
| const char RefStepToken = ':'; |
| Position = In.find(RefStepToken); |
| if (Position == StringRef::npos) |
| return false; |
| |
| StringRef RefStepString = In.substr(Position + 1); |
| // Allow exactly one numeric character for the additional refinement |
| // step parameter. |
| if (RefStepString.size() == 1) { |
| char RefStepChar = RefStepString[0]; |
| if (RefStepChar >= '0' && RefStepChar <= '9') { |
| Value = RefStepChar - '0'; |
| return true; |
| } |
| } |
| report_fatal_error("Invalid refinement step for -recip."); |
| } |
| |
| bool TargetRecip::parseGlobalParams(const std::string &Arg) { |
| StringRef ArgSub = Arg; |
| |
| // Look for an optional setting of the number of refinement steps needed |
| // for this type of reciprocal operation. |
| size_t RefPos; |
| uint8_t RefSteps; |
| StringRef RefStepString; |
| if (parseRefinementStep(ArgSub, RefPos, RefSteps)) { |
| // Split the string for further processing. |
| RefStepString = ArgSub.substr(RefPos + 1); |
| ArgSub = ArgSub.substr(0, RefPos); |
| } |
| bool Enable; |
| bool UseDefaults; |
| if (ArgSub == "all") { |
| UseDefaults = false; |
| Enable = true; |
| } else if (ArgSub == "none") { |
| UseDefaults = false; |
| Enable = false; |
| } else if (ArgSub == "default") { |
| UseDefaults = true; |
| } else { |
| // Any other string is invalid or an individual setting. |
| return false; |
| } |
| |
| // All enable values will be initialized to target defaults if 'default' was |
| // specified. |
| if (!UseDefaults) |
| for (auto &KV : RecipMap) |
| KV.second.Enabled = Enable; |
| |
| // Custom refinement count was specified with all, none, or default. |
| if (!RefStepString.empty()) |
| for (auto &KV : RecipMap) |
| KV.second.RefinementSteps = RefSteps; |
| |
| return true; |
| } |
| |
| void TargetRecip::parseIndividualParams(const std::vector<std::string> &Args) { |
| static const char DisabledPrefix = '!'; |
| unsigned NumArgs = Args.size(); |
| |
| for (unsigned i = 0; i != NumArgs; ++i) { |
| StringRef Val = Args[i]; |
| |
| bool IsDisabled = Val[0] == DisabledPrefix; |
| // Ignore the disablement token for string matching. |
| if (IsDisabled) |
| Val = Val.substr(1); |
| |
| size_t RefPos; |
| uint8_t RefSteps; |
| StringRef RefStepString; |
| if (parseRefinementStep(Val, RefPos, RefSteps)) { |
| // Split the string for further processing. |
| RefStepString = Val.substr(RefPos + 1); |
| Val = Val.substr(0, RefPos); |
| } |
| |
| RecipIter Iter = RecipMap.find(Val); |
| if (Iter == RecipMap.end()) { |
| // Try again specifying float suffix. |
| Iter = RecipMap.find(Val.str() + 'f'); |
| if (Iter == RecipMap.end()) { |
| Iter = RecipMap.find(Val.str() + 'd'); |
| assert(Iter == RecipMap.end() && "Float entry missing from map"); |
| report_fatal_error("Invalid option for -recip."); |
| } |
| |
| // The option was specified without a float or double suffix. |
| if (RecipMap[Val.str() + 'd'].Enabled != Uninitialized) { |
| // Make sure that the double entry was not already specified. |
| // The float entry will be checked below. |
| report_fatal_error("Duplicate option for -recip."); |
| } |
| } |
| |
| if (Iter->second.Enabled != Uninitialized) |
| report_fatal_error("Duplicate option for -recip."); |
| |
| // Mark the matched option as found. Do not allow duplicate specifiers. |
| Iter->second.Enabled = !IsDisabled; |
| if (!RefStepString.empty()) |
| Iter->second.RefinementSteps = RefSteps; |
| |
| // If the precision was not specified, the double entry is also initialized. |
| if (Val.back() != 'f' && Val.back() != 'd') { |
| RecipParams &Params = RecipMap[Val.str() + 'd']; |
| Params.Enabled = !IsDisabled; |
| if (!RefStepString.empty()) |
| Params.RefinementSteps = RefSteps; |
| } |
| } |
| } |
| |
| TargetRecip::TargetRecip(const std::vector<std::string> &Args) : |
| TargetRecip() { |
| unsigned NumArgs = Args.size(); |
| |
| // Check if "all", "default", or "none" was specified. |
| if (NumArgs == 1 && parseGlobalParams(Args[0])) |
| return; |
| |
| parseIndividualParams(Args); |
| } |
| |
| bool TargetRecip::isEnabled(StringRef Key) const { |
| ConstRecipIter Iter = RecipMap.find(Key); |
| assert(Iter != RecipMap.end() && "Unknown name for reciprocal map"); |
| assert(Iter->second.Enabled != Uninitialized && |
| "Enablement setting was not initialized"); |
| return Iter->second.Enabled; |
| } |
| |
| unsigned TargetRecip::getRefinementSteps(StringRef Key) const { |
| ConstRecipIter Iter = RecipMap.find(Key); |
| assert(Iter != RecipMap.end() && "Unknown name for reciprocal map"); |
| assert(Iter->second.RefinementSteps != Uninitialized && |
| "Refinement step setting was not initialized"); |
| return Iter->second.RefinementSteps; |
| } |
| |
| /// Custom settings (previously initialized values) override target defaults. |
| void TargetRecip::setDefaults(StringRef Key, bool Enable, |
| unsigned RefSteps) { |
| if (Key == "all") { |
| for (auto &KV : RecipMap) { |
| RecipParams &RP = KV.second; |
| if (RP.Enabled == Uninitialized) |
| RP.Enabled = Enable; |
| if (RP.RefinementSteps == Uninitialized) |
| RP.RefinementSteps = RefSteps; |
| } |
| } else { |
| RecipParams &RP = RecipMap[Key]; |
| if (RP.Enabled == Uninitialized) |
| RP.Enabled = Enable; |
| if (RP.RefinementSteps == Uninitialized) |
| RP.RefinementSteps = RefSteps; |
| } |
| } |
| |
| bool TargetRecip::operator==(const TargetRecip &Other) const { |
| for (const auto &KV : RecipMap) { |
| StringRef Op = KV.first; |
| const RecipParams &RP = KV.second; |
| const RecipParams &OtherRP = Other.RecipMap.find(Op)->second; |
| if (RP.RefinementSteps != OtherRP.RefinementSteps) |
| return false; |
| if (RP.Enabled != OtherRP.Enabled) |
| return false; |
| } |
| return true; |
| } |