Skip to content

[clang][bytecode] Implement more binary operators for fixed point types #110423

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1547,7 +1547,6 @@ bool Compiler<Emitter>::VisitFixedPointBinOp(const BinaryOperator *E) {
return this->emitEQFixedPoint(E);
case BO_NE:
return this->emitNEFixedPoint(E);
#if 0
case BO_LT:
return this->emitLTFixedPoint(E);
case BO_LE:
Expand All @@ -1556,9 +1555,14 @@ bool Compiler<Emitter>::VisitFixedPointBinOp(const BinaryOperator *E) {
return this->emitGTFixedPoint(E);
case BO_GE:
return this->emitGEFixedPoint(E);
#endif
case BO_Add:
return ConvertResult(this->emitAddFixedPoint(E));
case BO_Sub:
return ConvertResult(this->emitSubFixedPoint(E));
case BO_Mul:
return ConvertResult(this->emitMulFixedPoint(E));
case BO_Div:
return ConvertResult(this->emitDivFixedPoint(E));

default:
return this->emitInvalid(E);
Expand Down
39 changes: 33 additions & 6 deletions clang/lib/AST/ByteCode/FixedPoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ class FixedPoint final {
bool isNegative() const { return V.getValue().isNegative(); }
bool isPositive() const { return V.getValue().isNonNegative(); }
bool isMin() const {
return V.getValue() == APSInt::getMinValue(V.getSemantics().getWidth(),
!V.getSemantics().isSigned());
return V == llvm::APFixedPoint::getMin(V.getSemantics());
}
bool isMinusOne() const { return V.isSigned() && V.getValue() == -1; }

FixedPoint truncate(unsigned BitWidth) const { return *this; }

Expand All @@ -82,9 +82,12 @@ class FixedPoint final {
}

ComparisonCategoryResult compare(const FixedPoint &Other) const {
if (Other.V == V)
int c = V.compare(Other.V);
if (c == 0)
return ComparisonCategoryResult::Equal;
return ComparisonCategoryResult::Unordered;
else if (c < 0)
return ComparisonCategoryResult::Less;
return ComparisonCategoryResult::Greater;
}

static bool neg(const FixedPoint &A, FixedPoint *R) {
Expand All @@ -101,16 +104,40 @@ class FixedPoint final {
}
static bool sub(const FixedPoint A, const FixedPoint B, unsigned Bits,
FixedPoint *R) {
return true;
bool Overflow = false;
*R = FixedPoint(A.V.sub(B.V, &Overflow));
return Overflow;
}
static bool mul(const FixedPoint A, const FixedPoint B, unsigned Bits,
FixedPoint *R) {
return true;
bool Overflow = false;
*R = FixedPoint(A.V.mul(B.V, &Overflow));
return Overflow;
}
static bool div(const FixedPoint A, const FixedPoint B, unsigned Bits,
FixedPoint *R) {
bool Overflow = false;
*R = FixedPoint(A.V.div(B.V, &Overflow));
return Overflow;
}
static bool rem(const FixedPoint A, const FixedPoint B, unsigned Bits,
FixedPoint *R) {
llvm_unreachable("Rem doesn't exist for fixed point values");
return true;
}
static bool bitAnd(const FixedPoint A, const FixedPoint B, unsigned Bits,
FixedPoint *R) {
return true;
}
static bool bitOr(const FixedPoint A, const FixedPoint B, unsigned Bits,
FixedPoint *R) {
return true;
}
static bool bitXor(const FixedPoint A, const FixedPoint B, unsigned Bits,
FixedPoint *R) {
return true;
}

static bool increment(const FixedPoint &A, FixedPoint *R) { return true; }
static bool decrement(const FixedPoint &A, FixedPoint *R) { return true; }
};
Expand Down
12 changes: 11 additions & 1 deletion clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,10 +374,13 @@ bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
S.Stk.push<T>(Result);
return true;
}

// If for some reason evaluation continues, use the truncated results.
S.Stk.push<T>(Result);

// Short-circuit fixed-points here since the error handling is easier.
if constexpr (std::is_same_v<T, FixedPoint>)
return handleFixedPointOverflow(S, OpPC, Result);

// Slow path - compute the result using another bit of precision.
APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));

Expand Down Expand Up @@ -687,6 +690,13 @@ bool Div(InterpState &S, CodePtr OpPC) {
S.Stk.push<T>(Result);
return true;
}

if constexpr (std::is_same_v<T, FixedPoint>) {
if (handleFixedPointOverflow(S, OpPC, Result)) {
S.Stk.push<T>(Result);
return true;
}
}
return false;
}

Expand Down
7 changes: 6 additions & 1 deletion clang/lib/AST/ByteCode/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ def IntegerTypeClass : TypeClass {
Uint32, Sint64, Uint64, IntAP, IntAPS];
}

def IntegerAndFixedTypeClass : TypeClass {
let Types = [Sint8, Uint8, Sint16, Uint16, Sint32,
Uint32, Sint64, Uint64, IntAP, IntAPS, FixedPoint];
}

def FixedSizeIntegralTypeClass : TypeClass {
let Types = [Sint8, Uint8, Sint16, Uint16, Sint32,
Uint32, Sint64, Uint64, Bool];
Expand Down Expand Up @@ -146,7 +151,7 @@ class FloatOpcode : Opcode {
}

class IntegerOpcode : Opcode {
let Types = [IntegerTypeClass];
let Types = [IntegerAndFixedTypeClass];
let HasGroup = 1;
}

Expand Down
16 changes: 16 additions & 0 deletions clang/test/AST/ByteCode/fixed-point.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,26 @@ namespace BinOps {

static_assert(A + 100000 == 14.0k); // both-error {{is not an integral constant expression}} \
// both-note {{is outside the range of representable values}}

static_assert((A - A) == 0);
constexpr short _Accum mul_ovf1 = 255.0hk * 4.5hk; // both-error {{must be initialized by a constant expression}} \
// both-note {{value 123.5 is outside the range of representable values of type 'short _Accum'}}
constexpr short _Accum div_ovf1 = 255.0hk / 0.5hk; // both-error {{must be initialized by a constant expression}} \
// both-note {{value -2.0 is outside the range of representable values of type 'short _Accum'}}

}

namespace FixedPointCasts {
constexpr _Fract B = 0.3;
constexpr _Accum A = B;
constexpr _Fract C = A;
}

namespace Cmp {
constexpr _Accum A = 13.0k;
constexpr _Accum B = 14.0k;
static_assert(B > A);
static_assert(B >= A);
static_assert(A < B);
static_assert(A <= B);
}
Loading