310 lines · c
1//===--- Floating.h - Types for the constexpr VM ----------------*- 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-exception6//7//===----------------------------------------------------------------------===//8//9// Defines the VM types and helpers operating on types.10//11//===----------------------------------------------------------------------===//12 13#ifndef LLVM_CLANG_AST_INTERP_FLOATING_H14#define LLVM_CLANG_AST_INTERP_FLOATING_H15 16#include "Primitives.h"17#include "clang/AST/APValue.h"18#include "llvm/ADT/APFloat.h"19 20// XXX This is just a debugging help. Setting this to 1 will heap-allocate ALL21// floating values.22#define ALLOCATE_ALL 023 24namespace clang {25namespace interp {26 27using APFloat = llvm::APFloat;28using APSInt = llvm::APSInt;29using APInt = llvm::APInt;30 31/// If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY.32/// It will NOT copy the memory (unless, of course, copy() is called) and it33/// won't alllocate anything. The allocation should happen via InterpState or34/// Program.35class Floating final {36private:37 union {38 uint64_t Val = 0;39 uint64_t *Memory;40 };41 llvm::APFloatBase::Semantics Semantics;42 43 APFloat getValue() const {44 unsigned BitWidth = bitWidth();45 if (singleWord())46 return APFloat(getSemantics(), APInt(BitWidth, Val));47 unsigned NumWords = numWords();48 return APFloat(getSemantics(),49 APInt(BitWidth, llvm::ArrayRef(Memory, NumWords)));50 }51 52public:53 Floating() = default;54 Floating(llvm::APFloatBase::Semantics Semantics)55 : Val(0), Semantics(Semantics) {}56 Floating(const APFloat &F) {57 58 Semantics = llvm::APFloatBase::SemanticsToEnum(F.getSemantics());59 this->copy(F);60 }61 Floating(uint64_t *Memory, llvm::APFloatBase::Semantics Semantics)62 : Memory(Memory), Semantics(Semantics) {}63 64 APFloat getAPFloat() const { return getValue(); }65 66 bool operator<(Floating RHS) const { return getValue() < RHS.getValue(); }67 bool operator>(Floating RHS) const { return getValue() > RHS.getValue(); }68 bool operator<=(Floating RHS) const { return getValue() <= RHS.getValue(); }69 bool operator>=(Floating RHS) const { return getValue() >= RHS.getValue(); }70 71 APFloat::opStatus convertToInteger(APSInt &Result) const {72 bool IsExact;73 return getValue().convertToInteger(Result, llvm::APFloat::rmTowardZero,74 &IsExact);75 }76 77 void toSemantics(const llvm::fltSemantics *Sem, llvm::RoundingMode RM,78 Floating *Result) const {79 APFloat Copy = getValue();80 bool LosesInfo;81 Copy.convert(*Sem, RM, &LosesInfo);82 (void)LosesInfo;83 Result->copy(Copy);84 }85 86 APSInt toAPSInt(unsigned NumBits = 0) const {87 return APSInt(getValue().bitcastToAPInt());88 }89 APValue toAPValue(const ASTContext &) const { return APValue(getValue()); }90 void print(llvm::raw_ostream &OS) const {91 // Can't use APFloat::print() since it appends a newline.92 SmallVector<char, 16> Buffer;93 getValue().toString(Buffer);94 OS << Buffer;95 }96 std::string toDiagnosticString(const ASTContext &Ctx) const {97 std::string NameStr;98 llvm::raw_string_ostream OS(NameStr);99 print(OS);100 return NameStr;101 }102 103 unsigned bitWidth() const {104 return llvm::APFloatBase::semanticsSizeInBits(getSemantics());105 }106 unsigned numWords() const { return llvm::APInt::getNumWords(bitWidth()); }107 bool singleWord() const {108#if ALLOCATE_ALL109 return false;110#endif111 return numWords() == 1;112 }113 static bool singleWord(const llvm::fltSemantics &Sem) {114#if ALLOCATE_ALL115 return false;116#endif117 return APInt::getNumWords(llvm::APFloatBase::getSizeInBits(Sem)) == 1;118 }119 const llvm::fltSemantics &getSemantics() const {120 return llvm::APFloatBase::EnumToSemantics(Semantics);121 }122 123 void copy(const APFloat &F) {124 if (singleWord()) {125 Val = F.bitcastToAPInt().getZExtValue();126 } else {127 assert(Memory);128 std::memcpy(Memory, F.bitcastToAPInt().getRawData(),129 numWords() * sizeof(uint64_t));130 }131 }132 133 void take(uint64_t *NewMemory) {134 if (singleWord())135 return;136 137 if (Memory)138 std::memcpy(NewMemory, Memory, numWords() * sizeof(uint64_t));139 Memory = NewMemory;140 }141 142 bool isSigned() const { return true; }143 bool isNegative() const { return getValue().isNegative(); }144 bool isZero() const { return getValue().isZero(); }145 bool isNonZero() const { return getValue().isNonZero(); }146 bool isMin() const { return getValue().isSmallest(); }147 bool isMinusOne() const { return getValue().isExactlyValue(-1.0); }148 bool isNan() const { return getValue().isNaN(); }149 bool isSignaling() const { return getValue().isSignaling(); }150 bool isInf() const { return getValue().isInfinity(); }151 bool isFinite() const { return getValue().isFinite(); }152 bool isNormal() const { return getValue().isNormal(); }153 bool isDenormal() const { return getValue().isDenormal(); }154 llvm::FPClassTest classify() const { return getValue().classify(); }155 APFloat::fltCategory getCategory() const { return getValue().getCategory(); }156 157 ComparisonCategoryResult compare(const Floating &RHS) const {158 llvm::APFloatBase::cmpResult CmpRes = getValue().compare(RHS.getValue());159 switch (CmpRes) {160 case llvm::APFloatBase::cmpLessThan:161 return ComparisonCategoryResult::Less;162 case llvm::APFloatBase::cmpEqual:163 return ComparisonCategoryResult::Equal;164 case llvm::APFloatBase::cmpGreaterThan:165 return ComparisonCategoryResult::Greater;166 case llvm::APFloatBase::cmpUnordered:167 return ComparisonCategoryResult::Unordered;168 }169 llvm_unreachable("Inavlid cmpResult value");170 }171 172 static APFloat::opStatus fromIntegral(APSInt Val,173 const llvm::fltSemantics &Sem,174 llvm::RoundingMode RM,175 Floating *Result) {176 APFloat F = APFloat(Sem);177 APFloat::opStatus Status = F.convertFromAPInt(Val, Val.isSigned(), RM);178 Result->copy(F);179 return Status;180 }181 182 static void bitcastFromMemory(const std::byte *Buff,183 const llvm::fltSemantics &Sem,184 Floating *Result) {185 size_t Size = APFloat::semanticsSizeInBits(Sem);186 llvm::APInt API(Size, true);187 llvm::LoadIntFromMemory(API, (const uint8_t *)Buff, Size / 8);188 Result->copy(APFloat(Sem, API));189 }190 191 void bitcastToMemory(std::byte *Buff) const {192 llvm::APInt API = getValue().bitcastToAPInt();193 llvm::StoreIntToMemory(API, (uint8_t *)Buff, bitWidth() / 8);194 }195 196 // === Serialization support ===197 size_t bytesToSerialize() const {198 return sizeof(Semantics) + (numWords() * sizeof(uint64_t));199 }200 201 void serialize(std::byte *Buff) const {202 std::memcpy(Buff, &Semantics, sizeof(Semantics));203 if (singleWord()) {204 std::memcpy(Buff + sizeof(Semantics), &Val, sizeof(uint64_t));205 } else {206 std::memcpy(Buff + sizeof(Semantics), Memory,207 numWords() * sizeof(uint64_t));208 }209 }210 211 static llvm::APFloatBase::Semantics212 deserializeSemantics(const std::byte *Buff) {213 return *reinterpret_cast<const llvm::APFloatBase::Semantics *>(Buff);214 }215 216 static void deserialize(const std::byte *Buff, Floating *Result) {217 llvm::APFloatBase::Semantics Semantics;218 std::memcpy(&Semantics, Buff, sizeof(Semantics));219 220 unsigned BitWidth = llvm::APFloat::semanticsSizeInBits(221 llvm::APFloatBase::EnumToSemantics(Semantics));222 unsigned NumWords = llvm::APInt::getNumWords(BitWidth);223 224 Result->Semantics = Semantics;225 if (NumWords == 1 && !ALLOCATE_ALL) {226 std::memcpy(&Result->Val, Buff + sizeof(Semantics), sizeof(uint64_t));227 } else {228 assert(Result->Memory);229 std::memcpy(Result->Memory, Buff + sizeof(Semantics),230 NumWords * sizeof(uint64_t));231 }232 }233 234 // -------235 236 static APFloat::opStatus add(const Floating &A, const Floating &B,237 llvm::RoundingMode RM, Floating *R) {238 APFloat LHS = A.getValue();239 APFloat RHS = B.getValue();240 241 auto Status = LHS.add(RHS, RM);242 R->copy(LHS);243 return Status;244 }245 246 static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM,247 Floating *R) {248 APFloat One(A.getSemantics(), 1);249 APFloat LHS = A.getValue();250 251 auto Status = LHS.add(One, RM);252 R->copy(LHS);253 return Status;254 }255 256 static APFloat::opStatus sub(const Floating &A, const Floating &B,257 llvm::RoundingMode RM, Floating *R) {258 APFloat LHS = A.getValue();259 APFloat RHS = B.getValue();260 261 auto Status = LHS.subtract(RHS, RM);262 R->copy(LHS);263 return Status;264 }265 266 static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM,267 Floating *R) {268 APFloat One(A.getSemantics(), 1);269 APFloat LHS = A.getValue();270 271 auto Status = LHS.subtract(One, RM);272 R->copy(LHS);273 return Status;274 }275 276 static APFloat::opStatus mul(const Floating &A, const Floating &B,277 llvm::RoundingMode RM, Floating *R) {278 279 APFloat LHS = A.getValue();280 APFloat RHS = B.getValue();281 282 auto Status = LHS.multiply(RHS, RM);283 R->copy(LHS);284 return Status;285 }286 287 static APFloat::opStatus div(const Floating &A, const Floating &B,288 llvm::RoundingMode RM, Floating *R) {289 APFloat LHS = A.getValue();290 APFloat RHS = B.getValue();291 292 auto Status = LHS.divide(RHS, RM);293 R->copy(LHS);294 return Status;295 }296 297 static bool neg(const Floating &A, Floating *R) {298 R->copy(-A.getValue());299 return false;300 }301};302 303llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating F);304Floating getSwappedBytes(Floating F);305 306} // namespace interp307} // namespace clang308 309#endif310