xref: /freebsd-src/contrib/llvm-project/llvm/utils/TableGen/Common/OptEmitter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===- OptEmitter.cpp - Helper for emitting options.----------- -----------===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric 
9*0fca6ea1SDimitry Andric #include "OptEmitter.h"
10*0fca6ea1SDimitry Andric #include "llvm/ADT/Twine.h"
11*0fca6ea1SDimitry Andric #include "llvm/TableGen/Error.h"
12*0fca6ea1SDimitry Andric #include "llvm/TableGen/Record.h"
13*0fca6ea1SDimitry Andric #include <cctype>
14*0fca6ea1SDimitry Andric #include <cstring>
15*0fca6ea1SDimitry Andric 
16*0fca6ea1SDimitry Andric namespace llvm {
17*0fca6ea1SDimitry Andric 
18*0fca6ea1SDimitry Andric // Ordering on Info. The logic should match with the consumer-side function in
19*0fca6ea1SDimitry Andric // llvm/Option/OptTable.h.
20*0fca6ea1SDimitry Andric // FIXME: Make this take StringRefs instead of null terminated strings to
21*0fca6ea1SDimitry Andric // simplify callers.
22*0fca6ea1SDimitry Andric static int StrCmpOptionName(const char *A, const char *B) {
23*0fca6ea1SDimitry Andric   const char *X = A, *Y = B;
24*0fca6ea1SDimitry Andric   char a = tolower(*A), b = tolower(*B);
25*0fca6ea1SDimitry Andric   while (a == b) {
26*0fca6ea1SDimitry Andric     if (a == '\0')
27*0fca6ea1SDimitry Andric       return strcmp(A, B);
28*0fca6ea1SDimitry Andric 
29*0fca6ea1SDimitry Andric     a = tolower(*++X);
30*0fca6ea1SDimitry Andric     b = tolower(*++Y);
31*0fca6ea1SDimitry Andric   }
32*0fca6ea1SDimitry Andric 
33*0fca6ea1SDimitry Andric   if (a == '\0') // A is a prefix of B.
34*0fca6ea1SDimitry Andric     return 1;
35*0fca6ea1SDimitry Andric   if (b == '\0') // B is a prefix of A.
36*0fca6ea1SDimitry Andric     return -1;
37*0fca6ea1SDimitry Andric 
38*0fca6ea1SDimitry Andric   // Otherwise lexicographic.
39*0fca6ea1SDimitry Andric   return (a < b) ? -1 : 1;
40*0fca6ea1SDimitry Andric }
41*0fca6ea1SDimitry Andric 
42*0fca6ea1SDimitry Andric int CompareOptionRecords(Record *const *Av, Record *const *Bv) {
43*0fca6ea1SDimitry Andric   const Record *A = *Av;
44*0fca6ea1SDimitry Andric   const Record *B = *Bv;
45*0fca6ea1SDimitry Andric 
46*0fca6ea1SDimitry Andric   // Sentinel options precede all others and are only ordered by precedence.
47*0fca6ea1SDimitry Andric   bool ASent = A->getValueAsDef("Kind")->getValueAsBit("Sentinel");
48*0fca6ea1SDimitry Andric   bool BSent = B->getValueAsDef("Kind")->getValueAsBit("Sentinel");
49*0fca6ea1SDimitry Andric   if (ASent != BSent)
50*0fca6ea1SDimitry Andric     return ASent ? -1 : 1;
51*0fca6ea1SDimitry Andric 
52*0fca6ea1SDimitry Andric   // Compare options by name, unless they are sentinels.
53*0fca6ea1SDimitry Andric   if (!ASent)
54*0fca6ea1SDimitry Andric     if (int Cmp = StrCmpOptionName(A->getValueAsString("Name").str().c_str(),
55*0fca6ea1SDimitry Andric                                    B->getValueAsString("Name").str().c_str()))
56*0fca6ea1SDimitry Andric       return Cmp;
57*0fca6ea1SDimitry Andric 
58*0fca6ea1SDimitry Andric   if (!ASent) {
59*0fca6ea1SDimitry Andric     std::vector<StringRef> APrefixes = A->getValueAsListOfStrings("Prefixes");
60*0fca6ea1SDimitry Andric     std::vector<StringRef> BPrefixes = B->getValueAsListOfStrings("Prefixes");
61*0fca6ea1SDimitry Andric 
62*0fca6ea1SDimitry Andric     for (std::vector<StringRef>::const_iterator APre = APrefixes.begin(),
63*0fca6ea1SDimitry Andric                                                 AEPre = APrefixes.end(),
64*0fca6ea1SDimitry Andric                                                 BPre = BPrefixes.begin(),
65*0fca6ea1SDimitry Andric                                                 BEPre = BPrefixes.end();
66*0fca6ea1SDimitry Andric          APre != AEPre && BPre != BEPre; ++APre, ++BPre) {
67*0fca6ea1SDimitry Andric       if (int Cmp = StrCmpOptionName(APre->str().c_str(), BPre->str().c_str()))
68*0fca6ea1SDimitry Andric         return Cmp;
69*0fca6ea1SDimitry Andric     }
70*0fca6ea1SDimitry Andric   }
71*0fca6ea1SDimitry Andric 
72*0fca6ea1SDimitry Andric   // Then by the kind precedence;
73*0fca6ea1SDimitry Andric   int APrec = A->getValueAsDef("Kind")->getValueAsInt("Precedence");
74*0fca6ea1SDimitry Andric   int BPrec = B->getValueAsDef("Kind")->getValueAsInt("Precedence");
75*0fca6ea1SDimitry Andric   if (APrec == BPrec && A->getValueAsListOfStrings("Prefixes") ==
76*0fca6ea1SDimitry Andric                             B->getValueAsListOfStrings("Prefixes")) {
77*0fca6ea1SDimitry Andric     PrintError(A->getLoc(), Twine("Option is equivalent to"));
78*0fca6ea1SDimitry Andric     PrintError(B->getLoc(), Twine("Other defined here"));
79*0fca6ea1SDimitry Andric     PrintFatalError("Equivalent Options found.");
80*0fca6ea1SDimitry Andric   }
81*0fca6ea1SDimitry Andric   return APrec < BPrec ? -1 : 1;
82*0fca6ea1SDimitry Andric }
83*0fca6ea1SDimitry Andric 
84*0fca6ea1SDimitry Andric } // namespace llvm
85