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 Tombstone,
35 Int,
36 Float,
37 };
38
39 MapInfoType InfoType;
40 CanQualType QType;
41 llvm::APSInt Int;
42 llvm::APFloat Float;
43
44 /// Default constructor that can create Empty or Tombstone info entries
45 explicit NSConstantNumberMapInfo(MapInfoType I = MapInfoType::Empty)
46 : InfoType(I), QType(), Int(), Float(0.0) {}
47
48 bool isEmptyOrTombstone() const {
49 return InfoType == MapInfoType::Empty || InfoType == MapInfoType::Tombstone;
50 }
51
52public:
53 NSConstantNumberMapInfo(CanQualType QT, const llvm::APSInt &V)
54 : InfoType(MapInfoType::Int), QType(QT), Int(V), Float(0.0) {}
55 NSConstantNumberMapInfo(CanQualType QT, const llvm::APFloat &V)
56 : InfoType(MapInfoType::Float), QType(QT), Int(), Float(V) {}
57
58 unsigned getHashValue() const {
59 assert(!isEmptyOrTombstone() && "Cannot hash empty or tombstone map info!");
60
61 unsigned QTypeHash = llvm::DenseMapInfo<QualType>::getHashValue(
62 llvm::DenseMapInfo<QualType>::getTombstoneKey());
63
64 if (InfoType == MapInfoType::Int)
65 return llvm::detail::combineHashValue((unsigned)Int.getZExtValue(),
66 QTypeHash);
67
68 assert(InfoType == MapInfoType::Float);
69 return llvm::detail::combineHashValue(
70 (unsigned)Float.bitcastToAPInt().getZExtValue(), QTypeHash);
71 }
72
73 static inline NSConstantNumberMapInfo getEmptyKey() {
74 return NSConstantNumberMapInfo();
75 }
76
77 static inline NSConstantNumberMapInfo getTombstoneKey() {
78 return NSConstantNumberMapInfo(MapInfoType::Tombstone);
79 }
80
81 bool operator==(const NSConstantNumberMapInfo &RHS) const {
82 if (InfoType != RHS.InfoType || QType != RHS.QType)
83 return false;
84
85 // Handle the empty and tombstone equality
86 if (isEmptyOrTombstone())
87 return true;
88
89 if (InfoType == MapInfoType::Int)
90 return llvm::APSInt::isSameValue(Int, RHS.Int);
91
92 assert(InfoType == MapInfoType::Float);
93
94 // handle -0, NaN, and infinities correctly
95 return Float.bitwiseIsEqual(RHS.Float);
96 }
97};
98
99using std::iota;
100
103 uint64_t Opts;
104
105public:
106 enum class Options : uint64_t { Sorted = 1 };
107
109 const ObjCDictionaryLiteral *E,
110 ArrayRef<std::pair<llvm::Constant *, llvm::Constant *>> KeysAndObjects,
111 const Options O = Options::Sorted) {
112 Opts = static_cast<uint64_t>(O);
113 uint64_t const NumElements = KeysAndObjects.size();
114
115 // Reserve the capacity for the sorted keys & values
116 Elements.reserve(NumElements);
117
118 // Setup the element indicies 0 ..< NumElements
119 SmallVector<size_t, 16> ElementIndicies(NumElements);
120 std::iota(ElementIndicies.begin(), ElementIndicies.end(), 0);
121
122 // Now perform the sorts and shift the indicies as needed
123 std::stable_sort(
124 ElementIndicies.begin(), ElementIndicies.end(),
125 [E, O](size_t LI, size_t RI) {
126 Expr *const LK = E->getKeyValueElement(LI).Key->IgnoreImpCasts();
127 Expr *const RK = E->getKeyValueElement(RI).Key->IgnoreImpCasts();
128
129 if (!isa<ObjCStringLiteral>(LK) || !isa<ObjCStringLiteral>(RK))
130 llvm_unreachable("Non-constant literals should not be sorted to "
131 "maintain existing behavior");
132
133 // NOTE: Using the `StringLiteral->getString()` since it checks that
134 // `chars` are 1 byte
135 StringRef LKS = cast<ObjCStringLiteral>(LK)->getString()->getString();
136 StringRef RKS = cast<ObjCStringLiteral>(RK)->getString()->getString();
137
138 // Do an alpha sort to aid in with de-dupe at link time
139 // `O(log n)` worst case lookup at runtime supported by `Foundation`
140 if (O == Options::Sorted)
141 return LKS < RKS;
142 llvm_unreachable("Unexpected `NSDictionaryBuilder::Options given");
143 });
144
145 // Finally use the sorted indicies to insert into `Elements`.
146 for (auto &Idx : ElementIndicies) {
147 Elements.push_back(KeysAndObjects[Idx]);
148 }
149 }
150
153 return Elements;
154 }
155
156 Options getOptions() const { return static_cast<Options>(Opts); }
157
158 uint64_t getNumElements() const { return Elements.size(); }
159};
160
161} // namespace CGObjCMacConstantLiteralUtil
162} // namespace CodeGen
163} // namespace clang
164
165namespace llvm {
166
167using namespace clang::CodeGen::CGObjCMacConstantLiteralUtil;
168
169template <> struct DenseMapInfo<NSConstantNumberMapInfo> {
173
177
178 static unsigned getHashValue(const NSConstantNumberMapInfo &S) {
179 return S.getHashValue();
180 }
181
182 static bool isEqual(const NSConstantNumberMapInfo &LHS,
183 const NSConstantNumberMapInfo &RHS) {
184 return LHS == RHS;
185 }
186};
187
188} // namespace llvm
189
190#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)