aboutsummaryrefslogtreecommitdiff
path: root/lib/Target/SubtargetFeature.cpp
blob: bcb8f751aacb76ede51599af93c4c398646f5c0b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
//===- SubtargetFeature.cpp - CPU characteristics Implementation ----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Jim Laskey and is distributed under the 
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the SubtargetFeature interface.
//
//===----------------------------------------------------------------------===//

#include "llvm/Target/SubtargetFeature.h"

#include <string>
#include <algorithm>
#include <vector>
#include <cassert>
#include <cctype>

using namespace llvm;

/// Splits a string of comma separated items in to a vector of strings.
void SubtargetFeatures::Split(std::vector<std::string> &V,
                              const std::string &S) {
  // Start at beginning of string.
  size_t Pos = 0;
  while (true) {
    // Find the next comma
    size_t Comma = S.find(',', Pos);
    // If no comma found then the the rest of the string is used
    if (Comma == std::string::npos) {
      // Add string to vector
      V.push_back(S.substr(Pos));
      break;
    }
    // Otherwise add substring to vector
    V.push_back(S.substr(Pos, Comma - Pos));
    // Advance to next item
    Pos = Comma + 1;
  }
}

/// Join a vector of strings to a string with a comma separating each element.
std::string SubtargetFeatures::Join(const std::vector<std::string> &V) {
  // Start with empty string.
  std::string Result;
  // If the vector is not empty 
  if (!V.empty()) {
    // Start with the CPU feature
    Result = V[0];
    // For each successive feature
    for (size_t i = 1; i < V.size(); i++) {
      // Add a comma
      Result += ",";
      // Add the feature
      Result += V[i];
    }
  }
  // Return the features string 
  return Result;
}

/// Convert a string to lowercase.
std::string SubtargetFeatures::toLower(const std::string &S) {
  // Copy the string
  std::string Result = S;
  // For each character in string
  for (size_t i = 0; i < Result.size(); i++) {
    // Convert character to lowercase
    Result[i] = std::tolower(Result[i]);
  }
  // Return the lowercased string
  return Result;
}

/// Adding features.
void SubtargetFeatures::AddFeature(const std::string &String,
                                   bool IsEnabled) {
  // Don't add empty features
  if (!String.empty()) {
    // Convert to lowercase, prepend flag and add to vector
    Features.push_back(PrependFlag(toLower(String), IsEnabled));
  }
}

/// Find item in array using binary search.
const SubtargetFeatureKV *
SubtargetFeatures::Find(const std::string &S,
                        const SubtargetFeatureKV *A, size_t L) {
  // Determine the end of the array
  const SubtargetFeatureKV *Hi = A + L;
  // Binary search the array
  const SubtargetFeatureKV *F = std::lower_bound(A, Hi, S);
  // If not found then return NULL
  if (F == Hi || std::string(F->Key) != S) return NULL;
  // Return the found array item
  return F;
}

/// Display help for feature choices.
void SubtargetFeatures::Help(const char *Heading,
          const SubtargetFeatureKV *Table, size_t TableSize) {
    // Determine the length of the longest key
    size_t MaxLen = 0;
    for (size_t i = 0; i < TableSize; i++)
      MaxLen = std::max(MaxLen, std::strlen(Table[i].Key));
    // Print heading
    std::cerr << "Help for " << Heading << " choices\n\n";
    // For each feature
    for (size_t i = 0; i < TableSize; i++) {
      // Compute required padding
      size_t Pad = MaxLen - std::strlen(Table[i].Key) + 1;
      // Print details
      std::cerr << Table[i].Key << std::string(Pad, ' ') << " - "
                << Table[i].Desc << "\n";
    }
    // Wrap it up
    std::cerr << "\n\n";
    // Leave tool
    exit(1);
}

/// Parse feature string for quick usage.
uint32_t SubtargetFeatures::Parse(const std::string &String,
                                  const std::string &DefaultCPU,
                                  const SubtargetFeatureKV *CPUTable,
                                  size_t CPUTableSize,
                                  const SubtargetFeatureKV *FeatureTable,
                                  size_t FeatureTableSize) {
  assert(CPUTable && "missing CPU table");
  assert(FeatureTable && "missing features table");
#ifndef NDEBUG
  for (size_t i = 1; i < CPUTableSize; i++) {
    assert(strcmp(CPUTable[i - 1].Key, CPUTable[i].Key) < 0 &&
           "CPU table is not sorted");
  }
  for (size_t i = 1; i < FeatureTableSize; i++) {
    assert(strcmp(FeatureTable[i - 1].Key, FeatureTable[i].Key) < 0 &&
          "CPU features table is not sorted");
  }
#endif
  std::vector<std::string> Features;    // Subtarget features as a vector
  uint32_t Bits = 0;                    // Resulting bits
  // Split up features
  Split(Features, String);
  // Check if default is needed
  if (Features[0].empty()) Features[0] = DefaultCPU;
  // Check for help
  if (Features[0] == "help") Help("CPU", CPUTable, CPUTableSize);
  // Find CPU entry
  const SubtargetFeatureKV *CPUEntry =
                            Find(Features[0], CPUTable, CPUTableSize);
  // If there is a match
  if (CPUEntry) {
    // Set base feature bits
    Bits = CPUEntry->Value;
  } else {
    std::cerr << Features[0]
              << " is not a recognized processor for this target"
              << " (ignoring processor)"
              << "\n";
  }
  // Iterate through each feature
  for (size_t i = 1; i < Features.size(); i++) {
    // Get next feature
    const std::string &Feature = Features[i];
    // Check for help
    if (Feature == "+help") Help("feature", FeatureTable, FeatureTableSize);
    // Find feature in table.
    const SubtargetFeatureKV *FeatureEntry =
                       Find(StripFlag(Feature), FeatureTable, FeatureTableSize);
    // If there is a match
    if (FeatureEntry) {
      // Enable/disable feature in bits
      if (isEnabled(Feature)) Bits |=  FeatureEntry->Value;
      else                    Bits &= ~FeatureEntry->Value;
    } else {
      std::cerr << Feature
                << " is not a recognized feature for this target"
                << " (ignoring feature)"
                << "\n";
    }
  }
  return Bits;
}

/// Print feature string.
void SubtargetFeatures::print(std::ostream &OS) const {
  for (size_t i = 0; i < Features.size(); i++) {
    OS << Features[i] << "  ";
  }
  OS << "\n";
}

/// Dump feature info.
void SubtargetFeatures::dump() const {
  print(std::cerr);
}