================ @@ -0,0 +1,201 @@ +//===-- CodeGen/CGObjCMacConstantLiteralUtil.h - ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This should be used for things that effect the ABI of +// Obj-C constant initializer literals (`-fobjc-constant-literals`) to allow +// future changes without breaking the ABI promises. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_CODEGEN_CGOBJCMACCONSTANTLITERALUTIL_H +#define LLVM_CLANG_LIB_CODEGEN_CGOBJCMACCONSTANTLITERALUTIL_H + +#include "CGObjCRuntime.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/Type.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseMapInfo.h" +#include <numeric> + +namespace clang { +namespace CodeGen { +namespace CGObjCMacConstantLiteralUtil { + +class NSConstantNumberMapInfo { + + enum class MapInfoType { + Empty, + Tombstone, + Int, + Float, + }; + + MapInfoType InfoType; + QualType QType; + llvm::APSInt Int; + llvm::APFloat Float; + + /// Default constructor that can create Empty or Tombstone info entries + explicit NSConstantNumberMapInfo(MapInfoType I = MapInfoType::Empty) + : InfoType(I), QType(QualType()), Int(), Float(0.0) {} + + bool isEmptyOrTombstone() const { + return InfoType == MapInfoType::Empty || InfoType == MapInfoType::Tombstone; + } + +public: + NSConstantNumberMapInfo(const QualType &QT, const llvm::APSInt &V) + : InfoType(MapInfoType::Int), QType(QT), Int(V), Float(0.0) {} + NSConstantNumberMapInfo(const QualType &QT, const llvm::APFloat &V) + : InfoType(MapInfoType::Float), QType(QT), Int(), Float(V) {} + + unsigned getHashValue() const { + assert(!isEmptyOrTombstone() && "Cannot hash empty or tombstone map info!"); + + unsigned QTypeHash = llvm::DenseMapInfo<QualType>::getHashValue( + llvm::DenseMapInfo<QualType>::getTombstoneKey()); + + if (InfoType == MapInfoType::Int) + return llvm::detail::combineHashValue((unsigned)Int.getZExtValue(), + QTypeHash); + + assert(InfoType == MapInfoType::Float); + return llvm::detail::combineHashValue( + (unsigned)Float.bitcastToAPInt().getZExtValue(), QTypeHash); + } + + static inline NSConstantNumberMapInfo getEmptyKey() { + return NSConstantNumberMapInfo(); + } + + static inline NSConstantNumberMapInfo getTombstoneKey() { + return NSConstantNumberMapInfo(MapInfoType::Tombstone); + } + + bool operator==(const NSConstantNumberMapInfo &RHS) const { + if (InfoType != RHS.InfoType || QType != RHS.QType) + return false; + + // Handle the empty and tombstone equality + if (isEmptyOrTombstone()) + return true; + + if (InfoType == MapInfoType::Int) + return llvm::APSInt::isSameValue(Int, RHS.Int); + + assert(InfoType == MapInfoType::Float); + + // handle -0, NaN, and infinities correctly + return Float.bitwiseIsEqual(RHS.Float); + } +}; + +using std::iota; + +class NSDictionaryBuilder { + SmallVector<llvm::Constant *, 16> Keys; + SmallVector<llvm::Constant *, 16> Objects; + uint64_t Opts; + +public: + enum class Options : uint64_t { Sorted = 1 }; + + NSDictionaryBuilder(const ObjCDictionaryLiteral *E, + const ArrayRef<llvm::Constant *> &KYS, + const ArrayRef<llvm::Constant *> &OBS, + const Options O = Options::Sorted) { + assert((KYS.size() == OBS.size()) && + "NSConstantDictionary requires key / value pairs!" + "keys and objects not of equal size!"); + + Opts = static_cast<uint64_t>(O); + uint64_t const NumElements = KYS.size(); + + // Reserve the capacity for the sorted keys & values + Keys.reserve(NumElements); + Objects.reserve(NumElements); + + // Setup the element indicies 0 ..< NumElements + SmallVector<size_t, 16> ElementIndicies; + ElementIndicies.reserve(NumElements); + for (size_t i = 0; i < NumElements; i++) { + ElementIndicies.push_back(i); + } + std::iota(ElementIndicies.begin(), ElementIndicies.end(), 0); ---------------- ahatanak wrote:
Indices are still needed here because we use the keys of `ObjCDictionaryLiteral` to sort the elements. We could refactor to avoid indices, but the tradeoff isn't obvious to me. https://github.com/llvm/llvm-project/pull/185130 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
