clang 23.0.0git
CGObjCMacConstantLiteralUtil.h
Go to the documentation of this file.
1//===-- CodeGen/CGObjCMacConstantLiteralUtil.h - ----------------*- C++ -*-===//
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// This should be used for things that effect the ABI of
10// Obj-C constant initializer literals (`-fobjc-constant-literals`) to allow
11// future changes without breaking the ABI promises.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_CLANG_LIB_CODEGEN_CGOBJCMACCONSTANTLITERALUTIL_H
16#define LLVM_CLANG_LIB_CODEGEN_CGOBJCMACCONSTANTLITERALUTIL_H
17
18#include "CGObjCRuntime.h"
19#include "clang/AST/ExprObjC.h"
20#include "clang/AST/Type.h"
21#include "llvm/ADT/APFloat.h"
22#include "llvm/ADT/APSInt.h"
23#include "llvm/ADT/DenseMapInfo.h"
24#include <numeric>
25
26namespace clang {
27namespace CodeGen {
29
30class NSConstantNumberMapInfo {
31
32 enum class MapInfoType {
33 Empty,
34 Int,
35 Float,
36 };
37
38 MapInfoType InfoType;
39 CanQualType QType;
40 llvm::APSInt Int;
41 llvm::APFloat Float;
42
43 /// Default constructor that can create an Empty info entry.
44 explicit NSConstantNumberMapInfo(MapInfoType I = MapInfoType::Empty)
45 : InfoType(I), QType(), Int(), Float(0.0) {}
46
47 bool isEmpty() const { return InfoType == MapInfoType::Empty; }
48
49public:
50 NSConstantNumberMapInfo(CanQualType QT, const llvm::APSInt &V)
51 : InfoType(MapInfoType::Int), QType(QT), Int(V), Float(0.0) {}
52 NSConstantNumberMapInfo(CanQualType QT, const llvm::APFloat &V)
53 : InfoType(MapInfoType::Float), QType(QT), Int(), Float(V) {}
54
55 unsigned getHashValue() const {
56 assert(!isEmpty() && "Cannot hash empty map info!");
57
58 unsigned QTypeHash = llvm::DenseMapInfo<QualType>::getHashValue(QType);
59
60 if (InfoType == MapInfoType::Int)
61 return llvm::detail::combineHashValue((unsigned)Int.getZExtValue(),
62 QTypeHash);
63
64 assert(InfoType == MapInfoType::Float);
65 return llvm::detail::combineHashValue(
66 (unsigned)Float.bitcastToAPInt().getZExtValue(), QTypeHash);
67 }
68
69 bool operator==(const NSConstantNumberMapInfo &RHS) const {
70 if (InfoType != RHS.InfoType || QType != RHS.QType)
71 return false;
72
73 // Handle the empty equality.
74 if (isEmpty())
75 return true;
76
77 if (InfoType == MapInfoType::Int)
78 return llvm::APSInt::isSameValue(Int, RHS.Int);
79
80 assert(InfoType == MapInfoType::Float);
81
82 // handle -0, NaN, and infinities correctly
83 return Float.bitwiseIsEqual(RHS.Float);
84 }
85};
86
87using std::iota;
88
91 uint64_t Opts;
92
93public:
94 enum class Options : uint64_t { Sorted = 1 };
95
97 const ObjCDictionaryLiteral *E,
98 ArrayRef<std::pair<llvm::Constant *, llvm::Constant *>> KeysAndObjects,
99 const Options O = Options::Sorted) {
100 Opts = static_cast<uint64_t>(O);
101 uint64_t const NumElements = KeysAndObjects.size();
102
103 // Reserve the capacity for the sorted keys & values
104 Elements.reserve(NumElements);
105
106 // Setup the element indicies 0 ..< NumElements
107 SmallVector<size_t, 16> ElementIndicies(NumElements);
108 std::iota(ElementIndicies.begin(), ElementIndicies.end(), 0);
109
110 // Now perform the sorts and shift the indicies as needed
111 std::stable_sort(
112 ElementIndicies.begin(), ElementIndicies.end(),
113 [E, O](size_t LI, size_t RI) {
114 Expr *const LK = E->getKeyValueElement(LI).Key->IgnoreImpCasts();
115 Expr *const RK = E->getKeyValueElement(RI).Key->IgnoreImpCasts();
116
117 if (!isa<ObjCStringLiteral>(LK) || !isa<ObjCStringLiteral>(RK))
118 llvm_unreachable("Non-constant literals should not be sorted to "
119 "maintain existing behavior");
120
121 // NOTE: Using the `StringLiteral->getString()` since it checks that
122 // `chars` are 1 byte
123 StringRef LKS = cast<ObjCStringLiteral>(LK)->getString()->getString();
124 StringRef RKS = cast<ObjCStringLiteral>(RK)->getString()->getString();
125
126 // Do an alpha sort to aid in with de-dupe at link time
127 // `O(log n)` worst case lookup at runtime supported by `Foundation`
128 if (O == Options::Sorted)
129 return LKS < RKS;
130 llvm_unreachable("Unexpected `NSDictionaryBuilder::Options given");
131 });
132
133 // Finally use the sorted indicies to insert into `Elements`.
134 for (auto &Idx : ElementIndicies) {
135 Elements.push_back(KeysAndObjects[Idx]);
136 }
137 }
138
141 return Elements;
142 }
143
144 Options getOptions() const { return static_cast<Options>(Opts); }
145
146 uint64_t getNumElements() const { return Elements.size(); }
147};
148
149} // namespace CGObjCMacConstantLiteralUtil
150} // namespace CodeGen
151} // namespace clang
152
153namespace llvm {
154
155using namespace clang::CodeGen::CGObjCMacConstantLiteralUtil;
156
157template <> struct DenseMapInfo<NSConstantNumberMapInfo> {
158 static unsigned getHashValue(const NSConstantNumberMapInfo &S) {
159 return S.getHashValue();
160 }
161
162 static bool isEqual(const NSConstantNumberMapInfo &LHS,
163 const NSConstantNumberMapInfo &RHS) {
164 return LHS == RHS;
165 }
166};
167
168} // namespace llvm
169
170#endif
#define V(N, I)
C Language Family Type Representation.
NSDictionaryBuilder(const ObjCDictionaryLiteral *E, ArrayRef< std::pair< llvm::Constant *, llvm::Constant * > > KeysAndObjects, const Options O=Options::Sorted)
SmallVectorImpl< std::pair< llvm::Constant *, llvm::Constant * > > & getElements()
ObjCDictionaryLiteral - AST node to represent objective-c dictionary literals; as in:"name" : NSUserN...
Definition ExprObjC.h:342
The JSON file list parser is used to communicate input to InstallAPI.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30
static unsigned getHashValue(const NSConstantNumberMapInfo &S)
static bool isEqual(const NSConstantNumberMapInfo &LHS, const NSConstantNumberMapInfo &RHS)