Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -79,6 +79,7 @@ namespace clang { +class APFixedPoint; class APValue; class ASTMutationListener; class ASTRecordLayout; @@ -92,6 +93,7 @@ class CXXRecordDecl; class DiagnosticsEngine; class Expr; +class FixedPointSemantics; class MangleContext; class MangleNumberingContext; class MaterializeTemporaryExpr; @@ -1961,6 +1963,9 @@ unsigned char getFixedPointScale(QualType Ty) const; unsigned char getFixedPointIBits(QualType Ty) const; + FixedPointSemantics getFixedPointSemantics(QualType Ty) const; + APFixedPoint getFixedPointMax(QualType Ty) const; + APFixedPoint getFixedPointMin(QualType Ty) const; DeclarationNameInfo getNameForTemplate(TemplateName Name, SourceLocation NameLoc) const; Index: include/clang/Basic/FixedPoint.h =================================================================== --- /dev/null +++ include/clang/Basic/FixedPoint.h @@ -0,0 +1,138 @@ +//===- FixedPoint.h - Fixed point constant handling -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Defines the fixed point number interface. +/// This is a class for abstracting various operations performed on fixed point +/// types described in ISO/IEC JTC1 SC22 WG14 N1169 starting at clause 4. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_FIXEDPOINT_H +#define LLVM_CLANG_BASIC_FIXEDPOINT_H + +#include "llvm/ADT/APSInt.h" + +namespace clang { + +class ASTContext; +class QualType; + +/// The fixed point semantics work similarly to llvm::fltSemantics. The width +/// specifies the whole bit width of the underlying scaled integer (with padding +/// if any). The scale represents the number of fractional bits in this type. +/// When HasUnsignedPadding is true and this type is signed, the first bit +/// in the value this represents is treaded as padding. +class FixedPointSemantics { +public: + FixedPointSemantics(unsigned Width, unsigned Scale, bool IsSigned, + bool IsSaturated, bool HasUnsignedPadding) + : Width(Width), Scale(Scale), IsSigned(IsSigned), + IsSaturated(IsSaturated), HasUnsignedPadding(HasUnsignedPadding) { + assert(Width >= Scale && "Not enough room for the scale"); + } + + unsigned getWidth() const { return Width; } + unsigned getScale() const { return Scale; } + bool isSigned() const { return IsSigned; } + bool isSaturated() const { return IsSaturated; } + bool hasUnsignedPadding() const { return HasUnsignedPadding; } + + void setSaturated(bool Saturated) { IsSaturated = Saturated; } + + unsigned getIntegralBits() const { + if (IsSigned || (!IsSigned && HasUnsignedPadding)) + return Width - Scale - 1; + else + return Width - Scale; + } + +private: + unsigned Width; + unsigned Scale; + bool IsSigned; + bool IsSaturated; + bool HasUnsignedPadding; +}; + +/// The APFixedPoint class works similarly to APInt/APSInt in that it is a +/// functional replacement for a scaled integer. It is meant to replicate the +/// fixed point types proposed in ISO/IEC JTC1 SC22 WG14 N1169. The class carries +/// info about the fixed point type's width, sign, scale, and saturation, and +/// provides different operations that would normally be performed on fixed point +/// types. +/// +/// Semantically this does not represent any existing C type other than fixed +/// point types and should eventually be moved to LLVM if fixed point types gain +/// native IR support. +class APFixedPoint { + public: + APFixedPoint(const llvm::APInt &Val, const FixedPointSemantics &Sema) + : Val(Val, !Sema.isSigned()), Sema(Sema) { + assert(Val.getBitWidth() == Sema.getWidth() && + "The value should have a bit width that matches the Sema width"); + } + + APFixedPoint(uint64_t Val, const FixedPointSemantics &Sema) + : APFixedPoint(llvm::APInt(Sema.getWidth(), Val, Sema.isSigned()), + Sema) {} + + llvm::APSInt getValue() const { return llvm::APSInt(Val, !Sema.isSigned()); } + inline unsigned getWidth() const { return Sema.getWidth(); } + inline unsigned getScale() const { return Sema.getScale(); } + inline bool isSaturated() const { return Sema.isSaturated(); } + inline bool isSigned() const { return Sema.isSigned(); } + inline bool hasPadding() const { return Sema.hasUnsignedPadding(); } + + // Convert this number to match the semantics provided. + APFixedPoint convert(const FixedPointSemantics &DstSema) const; + + APFixedPoint shr(unsigned Amt) const { + return APFixedPoint(Val >> Amt, Sema); + } + + APFixedPoint shl(unsigned Amt) const { + return APFixedPoint(Val << Amt, Sema); + } + + llvm::APSInt getIntPart() const { + if (Val < 0 && Val != -Val) // Cover the case when we have the min val + return -(-Val >> getScale()); + else + return Val >> getScale(); + } + + // If LHS > RHS, return 1. If LHS == RHS, return 0. If LHS < RHS, return -1. + int compare(const APFixedPoint &Other) const; + bool operator==(const APFixedPoint &Other) const { + return compare(Other) == 0; + } + bool operator!=(const APFixedPoint &Other) const { + return compare(Other) != 0; + } + bool operator>(const APFixedPoint &Other) const { return compare(Other) > 0; } + bool operator<(const APFixedPoint &Other) const { return compare(Other) < 0; } + bool operator>=(const APFixedPoint &Other) const { + return compare(Other) >= 0; + } + bool operator<=(const APFixedPoint &Other) const { + return compare(Other) <= 0; + } + + static APFixedPoint getMax(const FixedPointSemantics &Sema); + static APFixedPoint getMin(const FixedPointSemantics &Sema); + +private: + llvm::APSInt Val; + FixedPointSemantics Sema; +}; + +} // namespace clang + +#endif Index: include/clang/Basic/TargetInfo.h =================================================================== --- include/clang/Basic/TargetInfo.h +++ include/clang/Basic/TargetInfo.h @@ -312,6 +312,14 @@ } } + /// In the event this target uses the same number of fractional bits for its + /// unsigned types as it does with its signed counterparts, there will be + /// exactly one bit of padding. + /// Return true if unsigned fixed point types have padding for this target. + bool doUnsignedFixedPointTypesHavePadding() const { + return PaddingOnUnsignedFixedPoint; + } + /// Return the width (in bits) of the specified integer type enum. /// /// For example, SignedInt -> getIntWidth(). Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -48,6 +48,7 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/CommentOptions.h" #include "clang/Basic/ExceptionSpecificationType.h" +#include "clang/Basic/FixedPoint.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" @@ -10433,3 +10434,22 @@ return 0; } } + +FixedPointSemantics ASTContext::getFixedPointSemantics(QualType Ty) const { + assert(Ty->isFixedPointType()); + bool isSigned = Ty->isSignedFixedPointType(); + return FixedPointSemantics( + static_cast(getTypeSize(Ty)), getFixedPointScale(Ty), isSigned, + Ty->isSaturatedFixedPointType(), + !isSigned && getTargetInfo().doUnsignedFixedPointTypesHavePadding()); +} + +APFixedPoint ASTContext::getFixedPointMax(QualType Ty) const { + assert(Ty->isFixedPointType()); + return APFixedPoint::getMax(getFixedPointSemantics(Ty)); +} + +APFixedPoint ASTContext::getFixedPointMin(QualType Ty) const { + assert(Ty->isFixedPointType()); + return APFixedPoint::getMin(getFixedPointSemantics(Ty)); +} Index: lib/Basic/CMakeLists.txt =================================================================== --- lib/Basic/CMakeLists.txt +++ lib/Basic/CMakeLists.txt @@ -54,6 +54,7 @@ DiagnosticOptions.cpp FileManager.cpp FileSystemStatCache.cpp + FixedPoint.cpp IdentifierTable.cpp LangOptions.cpp MemoryBufferCache.cpp Index: lib/Basic/FixedPoint.cpp =================================================================== --- /dev/null +++ lib/Basic/FixedPoint.cpp @@ -0,0 +1,115 @@ +//===- FixedPoint.cpp - Fixed point constant handling -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Defines the implementation for the fixed point number interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/Basic/FixedPoint.h" + +namespace clang { + +APFixedPoint APFixedPoint::convert(const FixedPointSemantics &DstSema) const { + llvm::APSInt NewVal = Val; + unsigned DstWidth = DstSema.getWidth(); + unsigned DstScale = DstSema.getScale(); + bool Upscaling = DstScale > getScale(); + + if (Upscaling) { + NewVal = NewVal.extend(NewVal.getBitWidth() + DstScale - getScale()); + NewVal <<= (DstScale - getScale()); + } else { + NewVal >>= (getScale() - DstScale); + } + + if (DstSema.isSaturated()) { + auto Mask = llvm::APInt::getBitsSetFrom( + NewVal.getBitWidth(), + std::min(DstScale + DstSema.getIntegralBits(), NewVal.getBitWidth())); + llvm::APInt Masked(NewVal & Mask); + + // Change in the bits above the sign + if (!(Masked == Mask || Masked == 0)) + NewVal = NewVal.isNegative() ? Mask : ~Mask; + + if (!DstSema.isSigned() && NewVal.isNegative()) + NewVal = 0; + } + + NewVal = NewVal.extOrTrunc(DstWidth); + NewVal.setIsSigned(DstSema.isSigned()); + return APFixedPoint(NewVal, DstSema); +} + +int APFixedPoint::compare(const APFixedPoint &Other) const { + llvm::APSInt ThisVal = getValue(); + llvm::APSInt OtherVal = Other.getValue(); + bool ThisSigned = Val.isSigned(); + bool OtherSigned = OtherVal.isSigned(); + unsigned OtherScale = Other.getScale(); + unsigned OtherWidth = OtherVal.getBitWidth(); + + unsigned CommonWidth = std::max(Val.getBitWidth(), OtherWidth); + + // Prevent overflow in the event the widths are the same but the scales differ + CommonWidth += std::abs(static_cast(getScale() - OtherScale)); + + ThisVal = ThisVal.extOrTrunc(CommonWidth); + OtherVal = OtherVal.extOrTrunc(CommonWidth); + + unsigned CommonScale = std::max(getScale(), OtherScale); + ThisVal = ThisVal.shl(CommonScale - getScale()); + OtherVal = OtherVal.shl(CommonScale - OtherScale); + + if (ThisSigned && OtherSigned) { + if (ThisVal.sgt(OtherVal)) + return 1; + else if (ThisVal.slt(OtherVal)) + return -1; + } else if (!ThisSigned && !OtherSigned) { + if (ThisVal.ugt(OtherVal)) + return 1; + else if (ThisVal.ult(OtherVal)) + return -1; + } else if (ThisSigned && !OtherSigned) { + if (ThisVal.isSignBitSet()) + return -1; + else if (ThisVal.ugt(OtherVal)) + return 1; + else if (ThisVal.ult(OtherVal)) + return -1; + } else { + // !ThisSigned && OtherSigned + if (OtherVal.isSignBitSet()) + return 1; + else if (ThisVal.ugt(OtherVal)) + return 1; + else if (ThisVal.ult(OtherVal)) + return -1; + } + + return 0; +} + +APFixedPoint APFixedPoint::getMax(const FixedPointSemantics &Sema) { + bool IsUnsigned = !Sema.isSigned(); + auto Val = llvm::APSInt::getMaxValue(Sema.getWidth(), IsUnsigned); + if (IsUnsigned && Sema.hasUnsignedPadding()) + Val = Val.lshr(1); + return APFixedPoint(Val, Sema); +} + +APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) { + auto Val = llvm::APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned()); + return APFixedPoint(Val, Sema); +} + +} // namespace clang Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -26,6 +26,7 @@ #include "clang/AST/ExprOpenMP.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" +#include "clang/Basic/FixedPoint.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -3363,16 +3364,14 @@ bool isSigned = !Literal.isUnsigned; unsigned scale = Context.getFixedPointScale(Ty); - unsigned ibits = Context.getFixedPointIBits(Ty); unsigned bit_width = Context.getTypeInfo(Ty).Width; llvm::APInt Val(bit_width, 0, isSigned); bool Overflowed = Literal.GetFixedPointValue(Val, scale); + bool ValIsZero = Val.isNullValue() && !Overflowed; - // Do not use bit_width since some types may have padding like _Fract or - // unsigned _Accums if PaddingOnUnsignedFixedPoint is set. - auto MaxVal = llvm::APInt::getMaxValue(ibits + scale).zextOrSelf(bit_width); - if (Literal.isFract && Val == MaxVal + 1) + auto MaxVal = Context.getFixedPointMax(Ty).getValue(); + if (Literal.isFract && Val == MaxVal + 1 && !ValIsZero) // Clause 6.4.4 - The value of a constant shall be in the range of // representable values for its type, with exception for constants of a // fract type with a value of exactly 1; such a constant shall denote Index: test/Frontend/fixed_point_declarations.c =================================================================== --- test/Frontend/fixed_point_declarations.c +++ test/Frontend/fixed_point_declarations.c @@ -1,5 +1,4 @@ // RUN: %clang -ffixed-point -S -emit-llvm %s -o - --target=x86_64-linux | FileCheck %s -// RUN: %clang -ffixed-point -S -emit-llvm %s -o - --target=x86_64-scei-ps4-ubuntu-fast | FileCheck %s // Primary fixed point types signed short _Accum s_short_accum; // CHECK-DAG: @s_short_accum = {{.*}}global i16 0, align 2 @@ -111,3 +110,18 @@ unsigned short _Fract u_short_fract_eps = 0x1p-8uhr; // CHECK-DAG: @u_short_fract_eps = {{.*}}global i8 1, align 1 unsigned _Fract u_fract_eps = 0x1p-16ur; // CHECK-DAG: @u_fract_eps = {{.*}}global i16 1, align 2 unsigned long _Fract u_long_fract_eps = 0x1p-32ulr; // CHECK-DAG: @u_long_fract_eps = {{.*}}global i32 1, align 4 + +// Zero +short _Accum short_accum_zero = 0.0hk; // CHECK-DAG: @short_accum_zero = {{.*}}global i16 0, align 2 + _Accum accum_zero = 0.0k; // CHECK-DAG: @accum_zero = {{.*}}global i32 0, align 4 +long _Accum long_accum_zero = 0.0lk; // CHECK-DAG: @long_accum_zero = {{.*}}global i64 0, align 8 +unsigned short _Accum u_short_accum_zero = 0.0uhk; // CHECK-DAG: @u_short_accum_zero = {{.*}}global i16 0, align 2 +unsigned _Accum u_accum_zero = 0.0uk; // CHECK-DAG: @u_accum_zero = {{.*}}global i32 0, align 4 +unsigned long _Accum u_long_accum_zero = 0.0ulk; // CHECK-DAG: @u_long_accum_zero = {{.*}}global i64 0, align 8 + +short _Fract short_fract_zero = 0.0hr; // CHECK-DAG: @short_fract_zero = {{.*}}global i8 0, align 1 + _Fract fract_zero = 0.0r; // CHECK-DAG: @fract_zero = {{.*}}global i16 0, align 2 +long _Fract long_fract_zero = 0.0lr; // CHECK-DAG: @long_fract_zero = {{.*}}global i32 0, align 4 +unsigned short _Fract u_short_fract_zero = 0.0uhr; // CHECK-DAG: @u_short_fract_zero = {{.*}}global i8 0, align 1 +unsigned _Fract u_fract_zero = 0.0ur; // CHECK-DAG: @u_fract_zero = {{.*}}global i16 0, align 2 +unsigned long _Fract u_long_fract_zero = 0.0ulr; // CHECK-DAG: @u_long_fract_zero = {{.*}}global i32 0, align 4 Index: unittests/Basic/CMakeLists.txt =================================================================== --- unittests/Basic/CMakeLists.txt +++ unittests/Basic/CMakeLists.txt @@ -6,6 +6,7 @@ CharInfoTest.cpp DiagnosticTest.cpp FileManagerTest.cpp + FixedPointTest.cpp MemoryBufferCacheTest.cpp SourceManagerTest.cpp VirtualFileSystemTest.cpp @@ -13,6 +14,7 @@ target_link_libraries(BasicTests PRIVATE + clangAST clangBasic clangLex ) Index: unittests/Basic/FixedPointTest.cpp =================================================================== --- /dev/null +++ unittests/Basic/FixedPointTest.cpp @@ -0,0 +1,683 @@ +//===- unittests/Basic/FixedPointTest.cpp -- fixed point number tests -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/FixedPoint.h" +#include "llvm/ADT/APSInt.h" +#include "gtest/gtest.h" + +using clang::APFixedPoint; +using clang::FixedPointSemantics; +using llvm::APInt; +using llvm::APSInt; + +namespace { + +FixedPointSemantics Saturated(FixedPointSemantics Sema) { + Sema.setSaturated(true); + return Sema; +} + +FixedPointSemantics getSAccumSema() { + return FixedPointSemantics(/*width=*/16, /*scale=*/7, /*isSigned=*/true, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getAccumSema() { + return FixedPointSemantics(/*width=*/32, /*scale=*/15, /*isSigned=*/true, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getLAccumSema() { + return FixedPointSemantics(/*width=*/64, /*scale=*/31, /*isSigned=*/true, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getSFractSema() { + return FixedPointSemantics(/*width=*/8, /*scale=*/7, /*isSigned=*/true, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getFractSema() { + return FixedPointSemantics(/*width=*/16, /*scale=*/15, /*isSigned=*/true, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getLFractSema() { + return FixedPointSemantics(/*width=*/32, /*scale=*/31, /*isSigned=*/true, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getUSAccumSema() { + return FixedPointSemantics(/*width=*/16, /*scale=*/8, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getUAccumSema() { + return FixedPointSemantics(/*width=*/32, /*scale=*/16, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getULAccumSema() { + return FixedPointSemantics(/*width=*/64, /*scale=*/32, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getUSFractSema() { + return FixedPointSemantics(/*width=*/8, /*scale=*/8, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getUFractSema() { + return FixedPointSemantics(/*width=*/16, /*scale=*/16, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getULFractSema() { + return FixedPointSemantics(/*width=*/32, /*scale=*/32, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/false); +} + +FixedPointSemantics getPadUSAccumSema() { + return FixedPointSemantics(/*width=*/16, /*scale=*/7, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/true); +} + +FixedPointSemantics getPadUAccumSema() { + return FixedPointSemantics(/*width=*/32, /*scale=*/15, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/true); +} + +FixedPointSemantics getPadULAccumSema() { + return FixedPointSemantics(/*width=*/64, /*scale=*/31, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/true); +} + +FixedPointSemantics getPadUSFractSema() { + return FixedPointSemantics(/*width=*/8, /*scale=*/7, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/true); +} + +FixedPointSemantics getPadUFractSema() { + return FixedPointSemantics(/*width=*/16, /*scale=*/15, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/true); +} + +FixedPointSemantics getPadULFractSema() { + return FixedPointSemantics(/*width=*/32, /*scale=*/31, /*isSigned=*/false, + /*isSaturated=*/false, + /*hasUnsignedPadding=*/true); +} + +void CheckUnpaddedMax(const FixedPointSemantics &Sema) { + ASSERT_EQ(APFixedPoint::getMax(Sema).getValue(), + APSInt::getMaxValue(Sema.getWidth(), !Sema.isSigned())); +} + +void CheckPaddedMax(const FixedPointSemantics &Sema) { + ASSERT_EQ(APFixedPoint::getMax(Sema).getValue(), + APSInt::getMaxValue(Sema.getWidth(), !Sema.isSigned()) >> 1); +} + +void CheckMin(const FixedPointSemantics &Sema) { + ASSERT_EQ(APFixedPoint::getMin(Sema).getValue(), + APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned())); +} + +TEST(FixedPointTest, getMax) { + CheckUnpaddedMax(getSAccumSema()); + CheckUnpaddedMax(getAccumSema()); + CheckUnpaddedMax(getLAccumSema()); + CheckUnpaddedMax(getUSAccumSema()); + CheckUnpaddedMax(getUAccumSema()); + CheckUnpaddedMax(getULAccumSema()); + CheckUnpaddedMax(getSFractSema()); + CheckUnpaddedMax(getFractSema()); + CheckUnpaddedMax(getLFractSema()); + CheckUnpaddedMax(getUSFractSema()); + CheckUnpaddedMax(getUFractSema()); + CheckUnpaddedMax(getULFractSema()); + + CheckPaddedMax(getPadUSAccumSema()); + CheckPaddedMax(getPadUAccumSema()); + CheckPaddedMax(getPadULAccumSema()); + CheckPaddedMax(getPadUSFractSema()); + CheckPaddedMax(getPadUFractSema()); + CheckPaddedMax(getPadULFractSema()); +} + +TEST(FixedPointTest, getMin) { + CheckMin(getSAccumSema()); + CheckMin(getAccumSema()); + CheckMin(getLAccumSema()); + CheckMin(getUSAccumSema()); + CheckMin(getUAccumSema()); + CheckMin(getULAccumSema()); + CheckMin(getSFractSema()); + CheckMin(getFractSema()); + CheckMin(getLFractSema()); + CheckMin(getUSFractSema()); + CheckMin(getUFractSema()); + CheckMin(getULFractSema()); + + CheckMin(getPadUSAccumSema()); + CheckMin(getPadUAccumSema()); + CheckMin(getPadULAccumSema()); + CheckMin(getPadUSFractSema()); + CheckMin(getPadUFractSema()); + CheckMin(getPadULFractSema()); +} + +void CheckIntPart(const FixedPointSemantics &Sema, int64_t IntPart) { + unsigned Scale = Sema.getScale(); + + // Value with a fraction + APFixedPoint ValWithFract(APInt(Sema.getWidth(), + (IntPart << Scale) + (1ULL << (Scale - 1)), + Sema.isSigned()), + Sema); + ASSERT_EQ(ValWithFract.getIntPart(), IntPart); + + // Just fraction + APFixedPoint JustFract( + APInt(Sema.getWidth(), (1ULL << (Scale - 1)), Sema.isSigned()), Sema); + ASSERT_EQ(JustFract.getIntPart(), 0); + + // Whole number + APFixedPoint WholeNum( + APInt(Sema.getWidth(), (IntPart << Scale), Sema.isSigned()), Sema); + ASSERT_EQ(WholeNum.getIntPart(), IntPart); + + // Negative + if (Sema.isSigned()) { + APFixedPoint Negative( + APInt(Sema.getWidth(), (IntPart << Scale), Sema.isSigned()), Sema); + ASSERT_EQ(Negative.getIntPart(), IntPart); + } +} + +void CheckIntPartMin(const FixedPointSemantics &Sema, int64_t Expected) { + ASSERT_EQ(APFixedPoint::getMin(Sema).getIntPart(), Expected); +} + +void CheckIntPartMax(const FixedPointSemantics &Sema, uint64_t Expected) { + ASSERT_EQ(APFixedPoint::getMax(Sema).getIntPart(), Expected); +} + +TEST(FixedPoint, getIntPart) { + // Normal values + CheckIntPart(getSAccumSema(), 2); + CheckIntPart(getAccumSema(), 2); + CheckIntPart(getLAccumSema(), 2); + CheckIntPart(getUSAccumSema(), 2); + CheckIntPart(getUAccumSema(), 2); + CheckIntPart(getULAccumSema(), 2); + + // Zero + CheckIntPart(getSAccumSema(), 0); + CheckIntPart(getAccumSema(), 0); + CheckIntPart(getLAccumSema(), 0); + CheckIntPart(getUSAccumSema(), 0); + CheckIntPart(getUAccumSema(), 0); + CheckIntPart(getULAccumSema(), 0); + + CheckIntPart(getSFractSema(), 0); + CheckIntPart(getFractSema(), 0); + CheckIntPart(getLFractSema(), 0); + CheckIntPart(getUSFractSema(), 0); + CheckIntPart(getUFractSema(), 0); + CheckIntPart(getULFractSema(), 0); + + // Min + CheckIntPartMin(getSAccumSema(), -256); + CheckIntPartMin(getAccumSema(), -65536); + CheckIntPartMin(getLAccumSema(), -4294967296); + + CheckIntPartMin(getSFractSema(), -1); + CheckIntPartMin(getFractSema(), -1); + CheckIntPartMin(getLFractSema(), -1); + + // Max + CheckIntPartMax(getSAccumSema(), 255); + CheckIntPartMax(getAccumSema(), 65535); + CheckIntPartMax(getLAccumSema(), 4294967295); + CheckIntPartMax(getUSAccumSema(), 255); + CheckIntPartMax(getUAccumSema(), 65535); + CheckIntPartMax(getULAccumSema(), 4294967295); + + CheckIntPartMax(getSFractSema(), 0); + CheckIntPartMax(getFractSema(), 0); + CheckIntPartMax(getLFractSema(), 0); + CheckIntPartMax(getUSFractSema(), 0); + CheckIntPartMax(getUFractSema(), 0); + CheckIntPartMax(getULFractSema(), 0); + + // Padded + // Normal Values + CheckIntPart(getPadUSAccumSema(), 2); + CheckIntPart(getPadUAccumSema(), 2); + CheckIntPart(getPadULAccumSema(), 2); + + // Zero + CheckIntPart(getPadUSAccumSema(), 0); + CheckIntPart(getPadUAccumSema(), 0); + CheckIntPart(getPadULAccumSema(), 0); + + CheckIntPart(getPadUSFractSema(), 0); + CheckIntPart(getPadUFractSema(), 0); + CheckIntPart(getPadULFractSema(), 0); + + // Max + CheckIntPartMax(getPadUSAccumSema(), 255); + CheckIntPartMax(getPadUAccumSema(), 65535); + CheckIntPartMax(getPadULAccumSema(), 4294967295); + + CheckIntPartMax(getPadUSFractSema(), 0); + CheckIntPartMax(getPadUFractSema(), 0); + CheckIntPartMax(getPadULFractSema(), 0); +} + +TEST(FixedPoint, compare) { + // Equality + // With fractional part (2.5) + // Across sizes + ASSERT_EQ(APFixedPoint(320, getSAccumSema()), + APFixedPoint(81920, getAccumSema())); + ASSERT_EQ(APFixedPoint(320, getSAccumSema()), + APFixedPoint(5368709120, getLAccumSema())); + ASSERT_EQ(APFixedPoint(0, getSAccumSema()), APFixedPoint(0, getLAccumSema())); + + // Across types (0.5) + ASSERT_EQ(APFixedPoint(64, getSAccumSema()), + APFixedPoint(64, getSFractSema())); + ASSERT_EQ(APFixedPoint(16384, getAccumSema()), + APFixedPoint(16384, getFractSema())); + ASSERT_EQ(APFixedPoint(1073741824, getLAccumSema()), + APFixedPoint(1073741824, getLFractSema())); + + // Across widths and types (0.5) + ASSERT_EQ(APFixedPoint(64, getSAccumSema()), + APFixedPoint(16384, getFractSema())); + ASSERT_EQ(APFixedPoint(64, getSAccumSema()), + APFixedPoint(1073741824, getLFractSema())); + + // Across saturation + ASSERT_EQ(APFixedPoint(320, getSAccumSema()), + APFixedPoint(81920, Saturated(getAccumSema()))); + + // Across signs + ASSERT_EQ(APFixedPoint(320, getSAccumSema()), + APFixedPoint(640, getUSAccumSema())); + ASSERT_EQ(APFixedPoint(-320, getSAccumSema()), + APFixedPoint(-81920, getAccumSema())); + + // Across padding + ASSERT_EQ(APFixedPoint(320, getSAccumSema()), + APFixedPoint(320, getPadUSAccumSema())); + ASSERT_EQ(APFixedPoint(640, getUSAccumSema()), + APFixedPoint(320, getPadUSAccumSema())); + + // Less than + ASSERT_LT(APFixedPoint(-1, getSAccumSema()), APFixedPoint(0, getAccumSema())); + ASSERT_LT(APFixedPoint(-1, getSAccumSema()), + APFixedPoint(0, getUAccumSema())); + ASSERT_LT(APFixedPoint(0, getSAccumSema()), APFixedPoint(1, getAccumSema())); + ASSERT_LT(APFixedPoint(0, getSAccumSema()), APFixedPoint(1, getUAccumSema())); + ASSERT_LT(APFixedPoint(0, getUSAccumSema()), APFixedPoint(1, getAccumSema())); + ASSERT_LT(APFixedPoint(0, getUSAccumSema()), + APFixedPoint(1, getUAccumSema())); + + // Greater than + ASSERT_GT(APFixedPoint(0, getAccumSema()), APFixedPoint(-1, getSAccumSema())); + ASSERT_GT(APFixedPoint(0, getUAccumSema()), + APFixedPoint(-1, getSAccumSema())); + ASSERT_GT(APFixedPoint(1, getAccumSema()), APFixedPoint(0, getSAccumSema())); + ASSERT_GT(APFixedPoint(1, getUAccumSema()), APFixedPoint(0, getSAccumSema())); + ASSERT_GT(APFixedPoint(1, getAccumSema()), APFixedPoint(0, getUSAccumSema())); + ASSERT_GT(APFixedPoint(1, getUAccumSema()), + APFixedPoint(0, getUSAccumSema())); +} + +// Check that a fixed point value in one sema is the same in another sema +void CheckUnsaturatedConversion(FixedPointSemantics Src, + FixedPointSemantics Dst, int64_t TestVal) { + int64_t ScaledVal = TestVal; + if (Dst.getScale() > Src.getScale()) { + ScaledVal <<= (Dst.getScale() - Src.getScale()); + } else { + ScaledVal >>= (Src.getScale() - Dst.getScale()); + } + + APFixedPoint Fixed(TestVal, Src); + APFixedPoint Expected(ScaledVal, Dst); + ASSERT_EQ(Fixed.convert(Dst), Expected); +} + +// Check the value in a given fixed point sema overflows to the saturated min +// for another sema +void CheckSaturatedConversionMin(FixedPointSemantics Src, + FixedPointSemantics Dst, int64_t TestVal) { + APFixedPoint Fixed(TestVal, Src); + ASSERT_EQ(Fixed.convert(Dst), APFixedPoint::getMin(Dst)); +} + +// Check the value in a given fixed point sema overflows to the saturated max +// for another sema +void CheckSaturatedConversionMax(FixedPointSemantics Src, + FixedPointSemantics Dst, int64_t TestVal) { + APFixedPoint Fixed(TestVal, Src); + ASSERT_EQ(Fixed.convert(Dst), APFixedPoint::getMax(Dst)); +} + +// Check one signed _Accum sema converted to other sema for different values. +void CheckSignedAccumConversionsAgainstOthers(FixedPointSemantics Src, + int64_t OneVal) { + int64_t NormalVal = (OneVal * 2) + (OneVal / 2); // 2.5 + int64_t HalfVal = (OneVal / 2); // 0.5 + + // +Accums to Accums + CheckUnsaturatedConversion(Src, getSAccumSema(), NormalVal); + CheckUnsaturatedConversion(Src, getAccumSema(), NormalVal); + CheckUnsaturatedConversion(Src, getLAccumSema(), NormalVal); + CheckUnsaturatedConversion(Src, getUSAccumSema(), NormalVal); + CheckUnsaturatedConversion(Src, getUAccumSema(), NormalVal); + CheckUnsaturatedConversion(Src, getULAccumSema(), NormalVal); + CheckUnsaturatedConversion(Src, getPadUSAccumSema(), NormalVal); + CheckUnsaturatedConversion(Src, getPadUAccumSema(), NormalVal); + CheckUnsaturatedConversion(Src, getPadULAccumSema(), NormalVal); + + // -Accums to Accums + CheckUnsaturatedConversion(Src, getSAccumSema(), -NormalVal); + CheckUnsaturatedConversion(Src, getAccumSema(), -NormalVal); + CheckUnsaturatedConversion(Src, getLAccumSema(), -NormalVal); + CheckSaturatedConversionMin(Src, Saturated(getUSAccumSema()), -NormalVal); + CheckSaturatedConversionMin(Src, Saturated(getUAccumSema()), -NormalVal); + CheckSaturatedConversionMin(Src, Saturated(getULAccumSema()), -NormalVal); + CheckSaturatedConversionMin(Src, Saturated(getPadUSAccumSema()), -NormalVal); + CheckSaturatedConversionMin(Src, Saturated(getPadUAccumSema()), -NormalVal); + CheckSaturatedConversionMin(Src, Saturated(getPadULAccumSema()), -NormalVal); + + // +Accums to Fracts + CheckUnsaturatedConversion(Src, getSFractSema(), HalfVal); + CheckUnsaturatedConversion(Src, getFractSema(), HalfVal); + CheckUnsaturatedConversion(Src, getLFractSema(), HalfVal); + CheckUnsaturatedConversion(Src, getUSFractSema(), HalfVal); + CheckUnsaturatedConversion(Src, getUFractSema(), HalfVal); + CheckUnsaturatedConversion(Src, getULFractSema(), HalfVal); + CheckUnsaturatedConversion(Src, getPadUSFractSema(), HalfVal); + CheckUnsaturatedConversion(Src, getPadUFractSema(), HalfVal); + CheckUnsaturatedConversion(Src, getPadULFractSema(), HalfVal); + + // -Accums to Fracts + CheckUnsaturatedConversion(Src, getSFractSema(), -HalfVal); + CheckUnsaturatedConversion(Src, getFractSema(), -HalfVal); + CheckUnsaturatedConversion(Src, getLFractSema(), -HalfVal); + CheckSaturatedConversionMin(Src, Saturated(getUSFractSema()), -HalfVal); + CheckSaturatedConversionMin(Src, Saturated(getUFractSema()), -HalfVal); + CheckSaturatedConversionMin(Src, Saturated(getULFractSema()), -HalfVal); + CheckSaturatedConversionMin(Src, Saturated(getPadUSFractSema()), -HalfVal); + CheckSaturatedConversionMin(Src, Saturated(getPadUFractSema()), -HalfVal); + CheckSaturatedConversionMin(Src, Saturated(getPadULFractSema()), -HalfVal); + + // 0 to Accums + CheckUnsaturatedConversion(Src, getSAccumSema(), 0); + CheckUnsaturatedConversion(Src, getAccumSema(), 0); + CheckUnsaturatedConversion(Src, getLAccumSema(), 0); + CheckUnsaturatedConversion(Src, getUSAccumSema(), 0); + CheckUnsaturatedConversion(Src, getUAccumSema(), 0); + CheckUnsaturatedConversion(Src, getULAccumSema(), 0); + CheckUnsaturatedConversion(Src, getPadUSAccumSema(), 0); + CheckUnsaturatedConversion(Src, getPadUAccumSema(), 0); + CheckUnsaturatedConversion(Src, getPadULAccumSema(), 0); + + // 0 to Fracts + CheckUnsaturatedConversion(Src, getSFractSema(), 0); + CheckUnsaturatedConversion(Src, getFractSema(), 0); + CheckUnsaturatedConversion(Src, getLFractSema(), 0); + CheckUnsaturatedConversion(Src, getUSFractSema(), 0); + CheckUnsaturatedConversion(Src, getUFractSema(), 0); + CheckUnsaturatedConversion(Src, getULFractSema(), 0); + CheckUnsaturatedConversion(Src, getPadUSFractSema(), 0); + CheckUnsaturatedConversion(Src, getPadUFractSema(), 0); + CheckUnsaturatedConversion(Src, getPadULFractSema(), 0); +} + +// Check one unsigned _Accum sema converted to other sema for different +// values. +void CheckUnsignedAccumConversionsAgainstOthers(FixedPointSemantics Src, + int64_t OneVal) { + int64_t NormalVal = (OneVal * 2) + (OneVal / 2); // 2.5 + int64_t HalfVal = (OneVal / 2); // 0.5 + + // +UAccums to Accums + CheckUnsaturatedConversion(Src, getSAccumSema(), NormalVal); + CheckUnsaturatedConversion(Src, getAccumSema(), NormalVal); + CheckUnsaturatedConversion(Src, getLAccumSema(), NormalVal); + CheckUnsaturatedConversion(Src, getUSAccumSema(), NormalVal); + CheckUnsaturatedConversion(Src, getUAccumSema(), NormalVal); + CheckUnsaturatedConversion(Src, getULAccumSema(), NormalVal); + CheckUnsaturatedConversion(Src, getPadUSAccumSema(), NormalVal); + CheckUnsaturatedConversion(Src, getPadUAccumSema(), NormalVal); + CheckUnsaturatedConversion(Src, getPadULAccumSema(), NormalVal); + + // +UAccums to Fracts + CheckUnsaturatedConversion(Src, getSFractSema(), HalfVal); + CheckUnsaturatedConversion(Src, getFractSema(), HalfVal); + CheckUnsaturatedConversion(Src, getLFractSema(), HalfVal); + CheckUnsaturatedConversion(Src, getUSFractSema(), HalfVal); + CheckUnsaturatedConversion(Src, getUFractSema(), HalfVal); + CheckUnsaturatedConversion(Src, getULFractSema(), HalfVal); + CheckUnsaturatedConversion(Src, getPadUSFractSema(), HalfVal); + CheckUnsaturatedConversion(Src, getPadUFractSema(), HalfVal); + CheckUnsaturatedConversion(Src, getPadULFractSema(), HalfVal); +} + +TEST(FixedPoint, AccumConversions) { + // Normal conversions + CheckSignedAccumConversionsAgainstOthers(getSAccumSema(), 128); + CheckUnsignedAccumConversionsAgainstOthers(getUSAccumSema(), 256); + CheckSignedAccumConversionsAgainstOthers(getAccumSema(), 32768); + CheckUnsignedAccumConversionsAgainstOthers(getUAccumSema(), 65536); + CheckSignedAccumConversionsAgainstOthers(getLAccumSema(), 2147483648); + CheckUnsignedAccumConversionsAgainstOthers(getULAccumSema(), 4294967296); + + CheckUnsignedAccumConversionsAgainstOthers(getPadUSAccumSema(), 128); + CheckUnsignedAccumConversionsAgainstOthers(getPadUAccumSema(), 32768); + CheckUnsignedAccumConversionsAgainstOthers(getPadULAccumSema(), 2147483648); +} + +TEST(FixedPoint, AccumConversionOverflow) { + // To SAccum max limit (65536) + CheckSaturatedConversionMax(getLAccumSema(), Saturated(getAccumSema()), + 140737488355328); + CheckSaturatedConversionMax(getLAccumSema(), Saturated(getUAccumSema()), + 140737488355328); + CheckSaturatedConversionMax(getLAccumSema(), Saturated(getPadUAccumSema()), + 140737488355328); + CheckSaturatedConversionMax(getULAccumSema(), Saturated(getAccumSema()), + 281474976710656); + CheckSaturatedConversionMax(getULAccumSema(), Saturated(getUAccumSema()), + 281474976710656); + CheckSaturatedConversionMax(getULAccumSema(), Saturated(getPadUAccumSema()), + 281474976710656); + + CheckSaturatedConversionMax(getPadULAccumSema(), Saturated(getAccumSema()), + 140737488355328); + CheckSaturatedConversionMax(getPadULAccumSema(), Saturated(getUAccumSema()), + 140737488355328); + CheckSaturatedConversionMax(getPadULAccumSema(), + Saturated(getPadUAccumSema()), 140737488355328); + + // To SAccum min limit (-65536) + CheckSaturatedConversionMin(getLAccumSema(), Saturated(getAccumSema()), + -140737488355328); + CheckSaturatedConversionMin(getLAccumSema(), Saturated(getUAccumSema()), + -140737488355328); + CheckSaturatedConversionMin(getLAccumSema(), Saturated(getPadUAccumSema()), + -140737488355328); +} + +TEST(FixedPoint, SAccumConversionOverflow) { + // To SAccum max limit (256) + CheckSaturatedConversionMax(getAccumSema(), Saturated(getSAccumSema()), + 8388608); + CheckSaturatedConversionMax(getAccumSema(), Saturated(getUSAccumSema()), + 8388608); + CheckSaturatedConversionMax(getAccumSema(), Saturated(getPadUSAccumSema()), + 8388608); + CheckSaturatedConversionMax(getUAccumSema(), Saturated(getSAccumSema()), + 16777216); + CheckSaturatedConversionMax(getUAccumSema(), Saturated(getUSAccumSema()), + 16777216); + CheckSaturatedConversionMax(getUAccumSema(), Saturated(getPadUSAccumSema()), + 16777216); + CheckSaturatedConversionMax(getLAccumSema(), Saturated(getSAccumSema()), + 549755813888); + CheckSaturatedConversionMax(getLAccumSema(), Saturated(getUSAccumSema()), + 549755813888); + CheckSaturatedConversionMax(getLAccumSema(), Saturated(getPadUSAccumSema()), + 549755813888); + CheckSaturatedConversionMax(getULAccumSema(), Saturated(getSAccumSema()), + 1099511627776); + CheckSaturatedConversionMax(getULAccumSema(), Saturated(getUSAccumSema()), + 1099511627776); + CheckSaturatedConversionMax(getULAccumSema(), Saturated(getPadUSAccumSema()), + 1099511627776); + + CheckSaturatedConversionMax(getPadUAccumSema(), Saturated(getSAccumSema()), + 8388608); + CheckSaturatedConversionMax(getPadUAccumSema(), Saturated(getUSAccumSema()), + 8388608); + CheckSaturatedConversionMax(getPadUAccumSema(), + Saturated(getPadUSAccumSema()), 8388608); + CheckSaturatedConversionMax(getPadULAccumSema(), Saturated(getSAccumSema()), + 549755813888); + CheckSaturatedConversionMax(getPadULAccumSema(), Saturated(getUSAccumSema()), + 549755813888); + CheckSaturatedConversionMax(getPadULAccumSema(), + Saturated(getPadUSAccumSema()), 549755813888); + + // To SAccum min limit (-256) + CheckSaturatedConversionMin(getAccumSema(), Saturated(getSAccumSema()), + -8388608); + CheckSaturatedConversionMin(getAccumSema(), Saturated(getUSAccumSema()), + -8388608); + CheckSaturatedConversionMin(getAccumSema(), Saturated(getPadUSAccumSema()), + -8388608); + CheckSaturatedConversionMin(getLAccumSema(), Saturated(getSAccumSema()), + -549755813888); + CheckSaturatedConversionMin(getLAccumSema(), Saturated(getUSAccumSema()), + -549755813888); + CheckSaturatedConversionMin(getLAccumSema(), Saturated(getPadUSAccumSema()), + -549755813888); +} + +void CheckSaturatedConversionToFractMax(FixedPointSemantics Src, + int64_t OneVal) { + CheckSaturatedConversionMax(Src, Saturated(getSFractSema()), OneVal); + CheckSaturatedConversionMax(Src, Saturated(getFractSema()), OneVal); + CheckSaturatedConversionMax(Src, Saturated(getLFractSema()), OneVal); + CheckSaturatedConversionMax(Src, Saturated(getUSFractSema()), OneVal); + CheckSaturatedConversionMax(Src, Saturated(getUFractSema()), OneVal); + CheckSaturatedConversionMax(Src, Saturated(getPadULFractSema()), OneVal); + CheckSaturatedConversionMax(Src, Saturated(getPadUSFractSema()), OneVal); + CheckSaturatedConversionMax(Src, Saturated(getPadUFractSema()), OneVal); + CheckSaturatedConversionMax(Src, Saturated(getPadULFractSema()), OneVal); +} + +void CheckSaturatedConversionToFractMin(FixedPointSemantics Src, + int64_t MinusOneVal) { + CheckSaturatedConversionMin(Src, Saturated(getSFractSema()), MinusOneVal); + CheckSaturatedConversionMin(Src, Saturated(getFractSema()), MinusOneVal); + CheckSaturatedConversionMin(Src, Saturated(getLFractSema()), MinusOneVal); + CheckSaturatedConversionMin(Src, Saturated(getUSFractSema()), MinusOneVal); + CheckSaturatedConversionMin(Src, Saturated(getUFractSema()), MinusOneVal); + CheckSaturatedConversionMin(Src, Saturated(getPadULFractSema()), MinusOneVal); + CheckSaturatedConversionMin(Src, Saturated(getPadUSFractSema()), MinusOneVal); + CheckSaturatedConversionMin(Src, Saturated(getPadUFractSema()), MinusOneVal); + CheckSaturatedConversionMin(Src, Saturated(getPadULFractSema()), MinusOneVal); +} + +TEST(FixedPoint, OverflowConversionsToFract) { + CheckSaturatedConversionToFractMax(getSAccumSema(), 128); + CheckSaturatedConversionToFractMin(getSAccumSema(), -128); + CheckSaturatedConversionToFractMax(getAccumSema(), 32768); + CheckSaturatedConversionToFractMin(getAccumSema(), -32768); + CheckSaturatedConversionToFractMax(getLAccumSema(), 2147483648); + CheckSaturatedConversionToFractMin(getLAccumSema(), -2147483648); + + // Unsigned + CheckSaturatedConversionToFractMax(getUSAccumSema(), 256); + CheckSaturatedConversionToFractMax(getUAccumSema(), 65536); + CheckSaturatedConversionToFractMax(getULAccumSema(), 4294967296); + + // Padded unsigned + CheckSaturatedConversionToFractMax(getPadUSAccumSema(), 128); + CheckSaturatedConversionToFractMax(getPadUAccumSema(), 32768); + CheckSaturatedConversionToFractMax(getPadULAccumSema(), 2147483648); +} + +TEST(FixedPoint, GetValueSignAfterConversion) { + APFixedPoint Fixed(255 << 7, getSAccumSema()); + ASSERT_TRUE(Fixed.getValue().isSigned()); + APFixedPoint UFixed = Fixed.convert(getUSAccumSema()); + ASSERT_TRUE(UFixed.getValue().isUnsigned()); + ASSERT_EQ(UFixed.getValue(), APSInt::getUnsigned(255 << 8).extOrTrunc(16)); +} + +TEST(FixedPoint, ModularWrapAround) { + // Positive to negative + APFixedPoint Val = APFixedPoint(1ULL << 7, getSAccumSema()); + ASSERT_EQ(Val.convert(getLFractSema()).getValue(), -(1ULL << 31)); + + Val = APFixedPoint(1ULL << 23, getAccumSema()); + ASSERT_EQ(Val.convert(getSAccumSema()).getValue(), -(1ULL << 15)); + + Val = APFixedPoint(1ULL << 47, getLAccumSema()); + ASSERT_EQ(Val.convert(getAccumSema()).getValue(), -(1ULL << 31)); + + // Negative to positive + Val = APFixedPoint(/*-1.5*/ -192, getSAccumSema()); + ASSERT_EQ(Val.convert(getLFractSema()).getValue(), 1ULL << 30); + + Val = APFixedPoint(-(257 << 15), getAccumSema()); + ASSERT_EQ(Val.convert(getSAccumSema()).getValue(), 255 << 7); + + Val = APFixedPoint(-(65537ULL << 31), getLAccumSema()); + ASSERT_EQ(Val.convert(getAccumSema()).getValue(), 65535 << 15); + + // Signed to unsigned + Val = APFixedPoint(-(1 << 7), getSAccumSema()); + ASSERT_EQ(Val.convert(getUSAccumSema()).getValue(), 255 << 8); + + Val = APFixedPoint(-(1 << 15), getAccumSema()); + ASSERT_EQ(Val.convert(getUAccumSema()).getValue(), 65535ULL << 16); + + Val = APFixedPoint(-(1ULL << 31), getLAccumSema()); + ASSERT_EQ(Val.convert(getULAccumSema()).getValue().getZExtValue(), + 4294967295ULL << 32); +} + +} // namespace