Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/Floating.h
213799 views
//===--- Floating.h - Types for the constexpr VM ----------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Defines the VM types and helpers operating on types.9//10//===----------------------------------------------------------------------===//1112#ifndef LLVM_CLANG_AST_INTERP_FLOATING_H13#define LLVM_CLANG_AST_INTERP_FLOATING_H1415#include "Primitives.h"16#include "clang/AST/APValue.h"17#include "llvm/ADT/APFloat.h"1819// XXX This is just a debugging help. Setting this to 1 will heap-allocate ALL20// floating values.21#define ALLOCATE_ALL 02223namespace clang {24namespace interp {2526using APFloat = llvm::APFloat;27using APSInt = llvm::APSInt;28using APInt = llvm::APInt;2930/// If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY.31/// It will NOT copy the memory (unless, of course, copy() is called) and it32/// won't alllocate anything. The allocation should happen via InterpState or33/// Program.34class Floating final {35private:36union {37uint64_t Val = 0;38uint64_t *Memory;39};40llvm::APFloatBase::Semantics Semantics;4142APFloat getValue() const {43unsigned BitWidth = bitWidth();44if (singleWord())45return APFloat(getSemantics(), APInt(BitWidth, Val));46unsigned NumWords = numWords();47return APFloat(getSemantics(), APInt(BitWidth, NumWords, Memory));48}4950public:51Floating() = default;52Floating(llvm::APFloatBase::Semantics Semantics)53: Val(0), Semantics(Semantics) {}54Floating(const APFloat &F) {5556Semantics = llvm::APFloatBase::SemanticsToEnum(F.getSemantics());57this->copy(F);58}59Floating(uint64_t *Memory, llvm::APFloatBase::Semantics Semantics)60: Memory(Memory), Semantics(Semantics) {}6162APFloat getAPFloat() const { return getValue(); }6364bool operator<(Floating RHS) const { return getValue() < RHS.getValue(); }65bool operator>(Floating RHS) const { return getValue() > RHS.getValue(); }66bool operator<=(Floating RHS) const { return getValue() <= RHS.getValue(); }67bool operator>=(Floating RHS) const { return getValue() >= RHS.getValue(); }6869APFloat::opStatus convertToInteger(APSInt &Result) const {70bool IsExact;71return getValue().convertToInteger(Result, llvm::APFloat::rmTowardZero,72&IsExact);73}7475void toSemantics(const llvm::fltSemantics *Sem, llvm::RoundingMode RM,76Floating *Result) const {77APFloat Copy = getValue();78bool LosesInfo;79Copy.convert(*Sem, RM, &LosesInfo);80(void)LosesInfo;81Result->copy(Copy);82}8384APSInt toAPSInt(unsigned NumBits = 0) const {85return APSInt(getValue().bitcastToAPInt());86}87APValue toAPValue(const ASTContext &) const { return APValue(getValue()); }88void print(llvm::raw_ostream &OS) const {89// Can't use APFloat::print() since it appends a newline.90SmallVector<char, 16> Buffer;91getValue().toString(Buffer);92OS << Buffer;93}94std::string toDiagnosticString(const ASTContext &Ctx) const {95std::string NameStr;96llvm::raw_string_ostream OS(NameStr);97print(OS);98return NameStr;99}100101unsigned bitWidth() const {102return llvm::APFloatBase::semanticsSizeInBits(getSemantics());103}104unsigned numWords() const { return llvm::APInt::getNumWords(bitWidth()); }105bool singleWord() const {106#if ALLOCATE_ALL107return false;108#endif109return numWords() == 1;110}111static bool singleWord(const llvm::fltSemantics &Sem) {112#if ALLOCATE_ALL113return false;114#endif115return APInt::getNumWords(llvm::APFloatBase::getSizeInBits(Sem)) == 1;116}117const llvm::fltSemantics &getSemantics() const {118return llvm::APFloatBase::EnumToSemantics(Semantics);119}120121void copy(const APFloat &F) {122if (singleWord()) {123Val = F.bitcastToAPInt().getZExtValue();124} else {125assert(Memory);126std::memcpy(Memory, F.bitcastToAPInt().getRawData(),127numWords() * sizeof(uint64_t));128}129}130131void take(uint64_t *NewMemory) {132if (singleWord())133return;134135if (Memory)136std::memcpy(NewMemory, Memory, numWords() * sizeof(uint64_t));137Memory = NewMemory;138}139140bool isSigned() const { return true; }141bool isNegative() const { return getValue().isNegative(); }142bool isZero() const { return getValue().isZero(); }143bool isNonZero() const { return getValue().isNonZero(); }144bool isMin() const { return getValue().isSmallest(); }145bool isMinusOne() const { return getValue().isExactlyValue(-1.0); }146bool isNan() const { return getValue().isNaN(); }147bool isSignaling() const { return getValue().isSignaling(); }148bool isInf() const { return getValue().isInfinity(); }149bool isFinite() const { return getValue().isFinite(); }150bool isNormal() const { return getValue().isNormal(); }151bool isDenormal() const { return getValue().isDenormal(); }152llvm::FPClassTest classify() const { return getValue().classify(); }153APFloat::fltCategory getCategory() const { return getValue().getCategory(); }154155ComparisonCategoryResult compare(const Floating &RHS) const {156llvm::APFloatBase::cmpResult CmpRes = getValue().compare(RHS.getValue());157switch (CmpRes) {158case llvm::APFloatBase::cmpLessThan:159return ComparisonCategoryResult::Less;160case llvm::APFloatBase::cmpEqual:161return ComparisonCategoryResult::Equal;162case llvm::APFloatBase::cmpGreaterThan:163return ComparisonCategoryResult::Greater;164case llvm::APFloatBase::cmpUnordered:165return ComparisonCategoryResult::Unordered;166}167llvm_unreachable("Inavlid cmpResult value");168}169170static APFloat::opStatus fromIntegral(APSInt Val,171const llvm::fltSemantics &Sem,172llvm::RoundingMode RM,173Floating *Result) {174APFloat F = APFloat(Sem);175APFloat::opStatus Status = F.convertFromAPInt(Val, Val.isSigned(), RM);176Result->copy(F);177return Status;178}179180static void bitcastFromMemory(const std::byte *Buff,181const llvm::fltSemantics &Sem,182Floating *Result) {183size_t Size = APFloat::semanticsSizeInBits(Sem);184llvm::APInt API(Size, true);185llvm::LoadIntFromMemory(API, (const uint8_t *)Buff, Size / 8);186Result->copy(APFloat(Sem, API));187}188189void bitcastToMemory(std::byte *Buff) const {190llvm::APInt API = getValue().bitcastToAPInt();191llvm::StoreIntToMemory(API, (uint8_t *)Buff, bitWidth() / 8);192}193194// === Serialization support ===195size_t bytesToSerialize() const {196return sizeof(Semantics) + (numWords() * sizeof(uint64_t));197}198199void serialize(std::byte *Buff) const {200std::memcpy(Buff, &Semantics, sizeof(Semantics));201if (singleWord()) {202std::memcpy(Buff + sizeof(Semantics), &Val, sizeof(uint64_t));203} else {204std::memcpy(Buff + sizeof(Semantics), Memory,205numWords() * sizeof(uint64_t));206}207}208209static llvm::APFloatBase::Semantics210deserializeSemantics(const std::byte *Buff) {211return *reinterpret_cast<const llvm::APFloatBase::Semantics *>(Buff);212}213214static void deserialize(const std::byte *Buff, Floating *Result) {215llvm::APFloatBase::Semantics Semantics;216std::memcpy(&Semantics, Buff, sizeof(Semantics));217218unsigned BitWidth = llvm::APFloat::semanticsSizeInBits(219llvm::APFloatBase::EnumToSemantics(Semantics));220unsigned NumWords = llvm::APInt::getNumWords(BitWidth);221222Result->Semantics = Semantics;223if (NumWords == 1 && !ALLOCATE_ALL) {224std::memcpy(&Result->Val, Buff + sizeof(Semantics), sizeof(uint64_t));225} else {226assert(Result->Memory);227std::memcpy(Result->Memory, Buff + sizeof(Semantics),228NumWords * sizeof(uint64_t));229}230}231232// -------233234static APFloat::opStatus add(const Floating &A, const Floating &B,235llvm::RoundingMode RM, Floating *R) {236APFloat LHS = A.getValue();237APFloat RHS = B.getValue();238239auto Status = LHS.add(RHS, RM);240R->copy(LHS);241return Status;242}243244static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM,245Floating *R) {246APFloat One(A.getSemantics(), 1);247APFloat LHS = A.getValue();248249auto Status = LHS.add(One, RM);250R->copy(LHS);251return Status;252}253254static APFloat::opStatus sub(const Floating &A, const Floating &B,255llvm::RoundingMode RM, Floating *R) {256APFloat LHS = A.getValue();257APFloat RHS = B.getValue();258259auto Status = LHS.subtract(RHS, RM);260R->copy(LHS);261return Status;262}263264static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM,265Floating *R) {266APFloat One(A.getSemantics(), 1);267APFloat LHS = A.getValue();268269auto Status = LHS.subtract(One, RM);270R->copy(LHS);271return Status;272}273274static APFloat::opStatus mul(const Floating &A, const Floating &B,275llvm::RoundingMode RM, Floating *R) {276277APFloat LHS = A.getValue();278APFloat RHS = B.getValue();279280auto Status = LHS.multiply(RHS, RM);281R->copy(LHS);282return Status;283}284285static APFloat::opStatus div(const Floating &A, const Floating &B,286llvm::RoundingMode RM, Floating *R) {287APFloat LHS = A.getValue();288APFloat RHS = B.getValue();289290auto Status = LHS.divide(RHS, RM);291R->copy(LHS);292return Status;293}294295static bool neg(const Floating &A, Floating *R) {296R->copy(-A.getValue());297return false;298}299};300301llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating F);302Floating getSwappedBytes(Floating F);303304} // namespace interp305} // namespace clang306307#endif308309310