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