We have: /// Once all uses of this constructor are migrated to other constructors, /// consider marking this overload ""= delete" to prevent calls from being /// incorrectly bound to the APInt(unsigned, uint64_t, bool) constructor. LLVM_ABI APInt(unsigned numBits, unsigned numWords, const uint64_t bigVal[]); This patch migrates away from this soft-deprecated constructor.
310 lines
9.7 KiB
C++
310 lines
9.7 KiB
C++
//===--- Floating.h - Types for the constexpr VM ----------------*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Defines the VM types and helpers operating on types.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_CLANG_AST_INTERP_FLOATING_H
|
|
#define LLVM_CLANG_AST_INTERP_FLOATING_H
|
|
|
|
#include "Primitives.h"
|
|
#include "clang/AST/APValue.h"
|
|
#include "llvm/ADT/APFloat.h"
|
|
|
|
// XXX This is just a debugging help. Setting this to 1 will heap-allocate ALL
|
|
// floating values.
|
|
#define ALLOCATE_ALL 0
|
|
|
|
namespace clang {
|
|
namespace interp {
|
|
|
|
using APFloat = llvm::APFloat;
|
|
using APSInt = llvm::APSInt;
|
|
using APInt = llvm::APInt;
|
|
|
|
/// If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY.
|
|
/// It will NOT copy the memory (unless, of course, copy() is called) and it
|
|
/// won't alllocate anything. The allocation should happen via InterpState or
|
|
/// Program.
|
|
class Floating final {
|
|
private:
|
|
union {
|
|
uint64_t Val = 0;
|
|
uint64_t *Memory;
|
|
};
|
|
llvm::APFloatBase::Semantics Semantics;
|
|
|
|
APFloat getValue() const {
|
|
unsigned BitWidth = bitWidth();
|
|
if (singleWord())
|
|
return APFloat(getSemantics(), APInt(BitWidth, Val));
|
|
unsigned NumWords = numWords();
|
|
return APFloat(getSemantics(),
|
|
APInt(BitWidth, llvm::ArrayRef(Memory, NumWords)));
|
|
}
|
|
|
|
public:
|
|
Floating() = default;
|
|
Floating(llvm::APFloatBase::Semantics Semantics)
|
|
: Val(0), Semantics(Semantics) {}
|
|
Floating(const APFloat &F) {
|
|
|
|
Semantics = llvm::APFloatBase::SemanticsToEnum(F.getSemantics());
|
|
this->copy(F);
|
|
}
|
|
Floating(uint64_t *Memory, llvm::APFloatBase::Semantics Semantics)
|
|
: Memory(Memory), Semantics(Semantics) {}
|
|
|
|
APFloat getAPFloat() const { return getValue(); }
|
|
|
|
bool operator<(Floating RHS) const { return getValue() < RHS.getValue(); }
|
|
bool operator>(Floating RHS) const { return getValue() > RHS.getValue(); }
|
|
bool operator<=(Floating RHS) const { return getValue() <= RHS.getValue(); }
|
|
bool operator>=(Floating RHS) const { return getValue() >= RHS.getValue(); }
|
|
|
|
APFloat::opStatus convertToInteger(APSInt &Result) const {
|
|
bool IsExact;
|
|
return getValue().convertToInteger(Result, llvm::APFloat::rmTowardZero,
|
|
&IsExact);
|
|
}
|
|
|
|
void toSemantics(const llvm::fltSemantics *Sem, llvm::RoundingMode RM,
|
|
Floating *Result) const {
|
|
APFloat Copy = getValue();
|
|
bool LosesInfo;
|
|
Copy.convert(*Sem, RM, &LosesInfo);
|
|
(void)LosesInfo;
|
|
Result->copy(Copy);
|
|
}
|
|
|
|
APSInt toAPSInt(unsigned NumBits = 0) const {
|
|
return APSInt(getValue().bitcastToAPInt());
|
|
}
|
|
APValue toAPValue(const ASTContext &) const { return APValue(getValue()); }
|
|
void print(llvm::raw_ostream &OS) const {
|
|
// Can't use APFloat::print() since it appends a newline.
|
|
SmallVector<char, 16> Buffer;
|
|
getValue().toString(Buffer);
|
|
OS << Buffer;
|
|
}
|
|
std::string toDiagnosticString(const ASTContext &Ctx) const {
|
|
std::string NameStr;
|
|
llvm::raw_string_ostream OS(NameStr);
|
|
print(OS);
|
|
return NameStr;
|
|
}
|
|
|
|
unsigned bitWidth() const {
|
|
return llvm::APFloatBase::semanticsSizeInBits(getSemantics());
|
|
}
|
|
unsigned numWords() const { return llvm::APInt::getNumWords(bitWidth()); }
|
|
bool singleWord() const {
|
|
#if ALLOCATE_ALL
|
|
return false;
|
|
#endif
|
|
return numWords() == 1;
|
|
}
|
|
static bool singleWord(const llvm::fltSemantics &Sem) {
|
|
#if ALLOCATE_ALL
|
|
return false;
|
|
#endif
|
|
return APInt::getNumWords(llvm::APFloatBase::getSizeInBits(Sem)) == 1;
|
|
}
|
|
const llvm::fltSemantics &getSemantics() const {
|
|
return llvm::APFloatBase::EnumToSemantics(Semantics);
|
|
}
|
|
|
|
void copy(const APFloat &F) {
|
|
if (singleWord()) {
|
|
Val = F.bitcastToAPInt().getZExtValue();
|
|
} else {
|
|
assert(Memory);
|
|
std::memcpy(Memory, F.bitcastToAPInt().getRawData(),
|
|
numWords() * sizeof(uint64_t));
|
|
}
|
|
}
|
|
|
|
void take(uint64_t *NewMemory) {
|
|
if (singleWord())
|
|
return;
|
|
|
|
if (Memory)
|
|
std::memcpy(NewMemory, Memory, numWords() * sizeof(uint64_t));
|
|
Memory = NewMemory;
|
|
}
|
|
|
|
bool isSigned() const { return true; }
|
|
bool isNegative() const { return getValue().isNegative(); }
|
|
bool isZero() const { return getValue().isZero(); }
|
|
bool isNonZero() const { return getValue().isNonZero(); }
|
|
bool isMin() const { return getValue().isSmallest(); }
|
|
bool isMinusOne() const { return getValue().isExactlyValue(-1.0); }
|
|
bool isNan() const { return getValue().isNaN(); }
|
|
bool isSignaling() const { return getValue().isSignaling(); }
|
|
bool isInf() const { return getValue().isInfinity(); }
|
|
bool isFinite() const { return getValue().isFinite(); }
|
|
bool isNormal() const { return getValue().isNormal(); }
|
|
bool isDenormal() const { return getValue().isDenormal(); }
|
|
llvm::FPClassTest classify() const { return getValue().classify(); }
|
|
APFloat::fltCategory getCategory() const { return getValue().getCategory(); }
|
|
|
|
ComparisonCategoryResult compare(const Floating &RHS) const {
|
|
llvm::APFloatBase::cmpResult CmpRes = getValue().compare(RHS.getValue());
|
|
switch (CmpRes) {
|
|
case llvm::APFloatBase::cmpLessThan:
|
|
return ComparisonCategoryResult::Less;
|
|
case llvm::APFloatBase::cmpEqual:
|
|
return ComparisonCategoryResult::Equal;
|
|
case llvm::APFloatBase::cmpGreaterThan:
|
|
return ComparisonCategoryResult::Greater;
|
|
case llvm::APFloatBase::cmpUnordered:
|
|
return ComparisonCategoryResult::Unordered;
|
|
}
|
|
llvm_unreachable("Inavlid cmpResult value");
|
|
}
|
|
|
|
static APFloat::opStatus fromIntegral(APSInt Val,
|
|
const llvm::fltSemantics &Sem,
|
|
llvm::RoundingMode RM,
|
|
Floating *Result) {
|
|
APFloat F = APFloat(Sem);
|
|
APFloat::opStatus Status = F.convertFromAPInt(Val, Val.isSigned(), RM);
|
|
Result->copy(F);
|
|
return Status;
|
|
}
|
|
|
|
static void bitcastFromMemory(const std::byte *Buff,
|
|
const llvm::fltSemantics &Sem,
|
|
Floating *Result) {
|
|
size_t Size = APFloat::semanticsSizeInBits(Sem);
|
|
llvm::APInt API(Size, true);
|
|
llvm::LoadIntFromMemory(API, (const uint8_t *)Buff, Size / 8);
|
|
Result->copy(APFloat(Sem, API));
|
|
}
|
|
|
|
void bitcastToMemory(std::byte *Buff) const {
|
|
llvm::APInt API = getValue().bitcastToAPInt();
|
|
llvm::StoreIntToMemory(API, (uint8_t *)Buff, bitWidth() / 8);
|
|
}
|
|
|
|
// === Serialization support ===
|
|
size_t bytesToSerialize() const {
|
|
return sizeof(Semantics) + (numWords() * sizeof(uint64_t));
|
|
}
|
|
|
|
void serialize(std::byte *Buff) const {
|
|
std::memcpy(Buff, &Semantics, sizeof(Semantics));
|
|
if (singleWord()) {
|
|
std::memcpy(Buff + sizeof(Semantics), &Val, sizeof(uint64_t));
|
|
} else {
|
|
std::memcpy(Buff + sizeof(Semantics), Memory,
|
|
numWords() * sizeof(uint64_t));
|
|
}
|
|
}
|
|
|
|
static llvm::APFloatBase::Semantics
|
|
deserializeSemantics(const std::byte *Buff) {
|
|
return *reinterpret_cast<const llvm::APFloatBase::Semantics *>(Buff);
|
|
}
|
|
|
|
static void deserialize(const std::byte *Buff, Floating *Result) {
|
|
llvm::APFloatBase::Semantics Semantics;
|
|
std::memcpy(&Semantics, Buff, sizeof(Semantics));
|
|
|
|
unsigned BitWidth = llvm::APFloat::semanticsSizeInBits(
|
|
llvm::APFloatBase::EnumToSemantics(Semantics));
|
|
unsigned NumWords = llvm::APInt::getNumWords(BitWidth);
|
|
|
|
Result->Semantics = Semantics;
|
|
if (NumWords == 1 && !ALLOCATE_ALL) {
|
|
std::memcpy(&Result->Val, Buff + sizeof(Semantics), sizeof(uint64_t));
|
|
} else {
|
|
assert(Result->Memory);
|
|
std::memcpy(Result->Memory, Buff + sizeof(Semantics),
|
|
NumWords * sizeof(uint64_t));
|
|
}
|
|
}
|
|
|
|
// -------
|
|
|
|
static APFloat::opStatus add(const Floating &A, const Floating &B,
|
|
llvm::RoundingMode RM, Floating *R) {
|
|
APFloat LHS = A.getValue();
|
|
APFloat RHS = B.getValue();
|
|
|
|
auto Status = LHS.add(RHS, RM);
|
|
R->copy(LHS);
|
|
return Status;
|
|
}
|
|
|
|
static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM,
|
|
Floating *R) {
|
|
APFloat One(A.getSemantics(), 1);
|
|
APFloat LHS = A.getValue();
|
|
|
|
auto Status = LHS.add(One, RM);
|
|
R->copy(LHS);
|
|
return Status;
|
|
}
|
|
|
|
static APFloat::opStatus sub(const Floating &A, const Floating &B,
|
|
llvm::RoundingMode RM, Floating *R) {
|
|
APFloat LHS = A.getValue();
|
|
APFloat RHS = B.getValue();
|
|
|
|
auto Status = LHS.subtract(RHS, RM);
|
|
R->copy(LHS);
|
|
return Status;
|
|
}
|
|
|
|
static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM,
|
|
Floating *R) {
|
|
APFloat One(A.getSemantics(), 1);
|
|
APFloat LHS = A.getValue();
|
|
|
|
auto Status = LHS.subtract(One, RM);
|
|
R->copy(LHS);
|
|
return Status;
|
|
}
|
|
|
|
static APFloat::opStatus mul(const Floating &A, const Floating &B,
|
|
llvm::RoundingMode RM, Floating *R) {
|
|
|
|
APFloat LHS = A.getValue();
|
|
APFloat RHS = B.getValue();
|
|
|
|
auto Status = LHS.multiply(RHS, RM);
|
|
R->copy(LHS);
|
|
return Status;
|
|
}
|
|
|
|
static APFloat::opStatus div(const Floating &A, const Floating &B,
|
|
llvm::RoundingMode RM, Floating *R) {
|
|
APFloat LHS = A.getValue();
|
|
APFloat RHS = B.getValue();
|
|
|
|
auto Status = LHS.divide(RHS, RM);
|
|
R->copy(LHS);
|
|
return Status;
|
|
}
|
|
|
|
static bool neg(const Floating &A, Floating *R) {
|
|
R->copy(-A.getValue());
|
|
return false;
|
|
}
|
|
};
|
|
|
|
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating F);
|
|
Floating getSwappedBytes(Floating F);
|
|
|
|
} // namespace interp
|
|
} // namespace clang
|
|
|
|
#endif
|