blob: 85876236a9998ece5fe3b76d18d5fb17ed2aff3e [file] [log] [blame]
//===--- 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"
namespace clang {
namespace interp {
using APFloat = llvm::APFloat;
using APSInt = llvm::APSInt;
class Floating final {
private:
// The underlying value storage.
APFloat F;
public:
/// Zero-initializes a Floating.
Floating() : F(0.0f) {}
Floating(const APFloat &F) : F(F) {}
// Static constructors for special floating point values.
static Floating getInf(const llvm::fltSemantics &Sem) {
return Floating(APFloat::getInf(Sem));
}
const APFloat &getAPFloat() const { return F; }
bool operator<(Floating RHS) const { return F < RHS.F; }
bool operator>(Floating RHS) const { return F > RHS.F; }
bool operator<=(Floating RHS) const { return F <= RHS.F; }
bool operator>=(Floating RHS) const { return F >= RHS.F; }
bool operator==(Floating RHS) const { return F == RHS.F; }
bool operator!=(Floating RHS) const { return F != RHS.F; }
Floating operator-() const { return Floating(-F); }
APFloat::opStatus convertToInteger(APSInt &Result) const {
bool IsExact;
return F.convertToInteger(Result, llvm::APFloat::rmTowardZero, &IsExact);
}
Floating toSemantics(const llvm::fltSemantics *Sem,
llvm::RoundingMode RM) const {
APFloat Copy = F;
bool LosesInfo;
Copy.convert(*Sem, RM, &LosesInfo);
(void)LosesInfo;
return Floating(Copy);
}
/// Convert this Floating to one with the same semantics as \Other.
Floating toSemantics(const Floating &Other, llvm::RoundingMode RM) const {
return toSemantics(&Other.F.getSemantics(), RM);
}
APSInt toAPSInt(unsigned NumBits = 0) const {
return APSInt(F.bitcastToAPInt());
}
APValue toAPValue() const { return APValue(F); }
void print(llvm::raw_ostream &OS) const {
// Can't use APFloat::print() since it appends a newline.
SmallVector<char, 16> Buffer;
F.toString(Buffer);
OS << Buffer;
}
unsigned bitWidth() const { return F.semanticsSizeInBits(F.getSemantics()); }
bool isSigned() const { return true; }
bool isNegative() const { return F.isNegative(); }
bool isPositive() const { return !F.isNegative(); }
bool isZero() const { return F.isZero(); }
bool isNonZero() const { return F.isNonZero(); }
bool isMin() const { return F.isSmallest(); }
bool isMinusOne() const { return F.isExactlyValue(-1.0); }
bool isNan() const { return F.isNaN(); }
bool isFinite() const { return F.isFinite(); }
ComparisonCategoryResult compare(const Floating &RHS) const {
return Compare(F, RHS.F);
}
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 = Floating(F);
return Status;
}
// -------
static APFloat::opStatus add(const Floating &A, const Floating &B,
llvm::RoundingMode RM, Floating *R) {
*R = Floating(A.F);
return R->F.add(B.F, RM);
}
static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM,
Floating *R) {
APFloat One(A.F.getSemantics(), 1);
*R = Floating(A.F);
return R->F.add(One, RM);
}
static APFloat::opStatus sub(const Floating &A, const Floating &B,
llvm::RoundingMode RM, Floating *R) {
*R = Floating(A.F);
return R->F.subtract(B.F, RM);
}
static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM,
Floating *R) {
APFloat One(A.F.getSemantics(), 1);
*R = Floating(A.F);
return R->F.subtract(One, RM);
}
static APFloat::opStatus mul(const Floating &A, const Floating &B,
llvm::RoundingMode RM, Floating *R) {
*R = Floating(A.F);
return R->F.multiply(B.F, RM);
}
static APFloat::opStatus div(const Floating &A, const Floating &B,
llvm::RoundingMode RM, Floating *R) {
*R = Floating(A.F);
return R->F.divide(B.F, RM);
}
static bool neg(const Floating &A, Floating *R) {
*R = -A;
return false;
}
};
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating F);
Floating getSwappedBytes(Floating F);
} // namespace interp
} // namespace clang
#endif