Skip to content

[clang][bytecode] Start implementing fixed point types #110216

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 27, 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
1 change: 1 addition & 0 deletions clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "ByteCodeEmitter.h"
#include "Context.h"
#include "FixedPoint.h"
#include "Floating.h"
#include "IntegralAP.h"
#include "Opcode.h"
Expand Down
18 changes: 16 additions & 2 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "Compiler.h"
#include "ByteCodeEmitter.h"
#include "Context.h"
#include "FixedPoint.h"
#include "Floating.h"
#include "Function.h"
#include "InterpShared.h"
Expand Down Expand Up @@ -470,6 +471,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
}

case CK_IntegralToBoolean:
case CK_FixedPointToBoolean:
case CK_BooleanToSignedIntegral:
case CK_IntegralCast: {
if (DiscardResult)
Expand Down Expand Up @@ -717,6 +719,16 @@ bool Compiler<Emitter>::VisitImaginaryLiteral(const ImaginaryLiteral *E) {
return this->visitArrayElemInit(1, SubExpr);
}

template <class Emitter>
bool Compiler<Emitter>::VisitFixedPointLiteral(const FixedPointLiteral *E) {
assert(E->getType()->isFixedPointType());
assert(classifyPrim(E) == PT_FixedPoint);

// FIXME: Semantics.
APInt Value = E->getValue();
return this->emitConstFixedPoint(Value, E);
}

template <class Emitter>
bool Compiler<Emitter>::VisitParenExpr(const ParenExpr *E) {
return this->delegate(E->getSubExpr());
Expand Down Expand Up @@ -3685,9 +3697,10 @@ bool Compiler<Emitter>::visitZeroInitializer(PrimType T, QualType QT,
return this->emitNullFnPtr(nullptr, E);
case PT_MemberPtr:
return this->emitNullMemberPtr(nullptr, E);
case PT_Float: {
case PT_Float:
return this->emitConstFloat(APFloat::getZero(Ctx.getFloatSemantics(QT)), E);
}
case PT_FixedPoint:
llvm_unreachable("Implement");
}
llvm_unreachable("unknown primitive type");
}
Expand Down Expand Up @@ -3798,6 +3811,7 @@ bool Compiler<Emitter>::emitConst(T Value, PrimType Ty, const Expr *E) {
case PT_Float:
case PT_IntAP:
case PT_IntAPS:
case PT_FixedPoint:
llvm_unreachable("Invalid integral type");
break;
}
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ByteCode/Compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
bool VisitIntegerLiteral(const IntegerLiteral *E);
bool VisitFloatingLiteral(const FloatingLiteral *E);
bool VisitImaginaryLiteral(const ImaginaryLiteral *E);
bool VisitFixedPointLiteral(const FixedPointLiteral *E);
bool VisitParenExpr(const ParenExpr *E);
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitLogicalBinOp(const BinaryOperator *E);
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/ByteCode/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ std::optional<PrimType> Context::classify(QualType T) const {
if (const auto *DT = dyn_cast<DecltypeType>(T))
return classify(DT->getUnderlyingType());

if (T->isFixedPointType())
return PT_FixedPoint;

return std::nullopt;
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ByteCode/Descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "Descriptor.h"
#include "Boolean.h"
#include "FixedPoint.h"
#include "Floating.h"
#include "FunctionPointer.h"
#include "IntegralAP.h"
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/ByteCode/Disasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "Boolean.h"
#include "Context.h"
#include "EvaluationResult.h"
#include "FixedPoint.h"
#include "Floating.h"
#include "Function.h"
#include "FunctionPointer.h"
Expand Down Expand Up @@ -126,6 +127,8 @@ static const char *primTypeToString(PrimType T) {
return "FnPtr";
case PT_MemberPtr:
return "MemberPtr";
case PT_FixedPoint:
return "FixedPoint";
}
llvm_unreachable("Unhandled PrimType");
}
Expand Down
63 changes: 63 additions & 0 deletions clang/lib/AST/ByteCode/FixedPoint.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//===------- FixedPoint.h - Fixedd point types for the 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_AST_INTERP_FIXED_POINT_H
#define LLVM_CLANG_AST_INTERP_FIXED_POINT_H

#include "clang/AST/APValue.h"
#include "clang/AST/ComparisonCategories.h"
#include "llvm/ADT/APFixedPoint.h"

namespace clang {
namespace interp {

using APInt = llvm::APInt;

/// Wrapper around fixed point types.
class FixedPoint final {
private:
llvm::APFixedPoint V;

public:
FixedPoint(APInt V)
: V(V,
llvm::FixedPointSemantics(V.getBitWidth(), 0, false, false, false)) {}
// This needs to be default-constructible so llvm::endian::read works.
FixedPoint()
: V(APInt(0, 0ULL, false),
llvm::FixedPointSemantics(0, 0, false, false, false)) {}

operator bool() const { return V.getBoolValue(); }
template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>
explicit operator Ty() const {
// FIXME
return 0;
}

void print(llvm::raw_ostream &OS) const { OS << V; }

APValue toAPValue(const ASTContext &) const { return APValue(V); }

ComparisonCategoryResult compare(const FixedPoint &Other) const {
if (Other.V == V)
return ComparisonCategoryResult::Equal;
return ComparisonCategoryResult::Unordered;
}
};

inline FixedPoint getSwappedBytes(FixedPoint F) { return F; }

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, FixedPoint F) {
F.print(OS);
return OS;
}

} // namespace interp
} // namespace clang

#endif
1 change: 1 addition & 0 deletions clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "../ExprConstShared.h"
#include "Boolean.h"
#include "DynamicAllocator.h"
#include "FixedPoint.h"
#include "Floating.h"
#include "Function.h"
#include "FunctionPointer.h"
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ByteCode/InterpStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "InterpStack.h"
#include "Boolean.h"
#include "FixedPoint.h"
#include "Floating.h"
#include "Integral.h"
#include "MemberPointer.h"
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/ByteCode/InterpStack.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#ifndef LLVM_CLANG_AST_INTERP_INTERPSTACK_H
#define LLVM_CLANG_AST_INTERP_INTERPSTACK_H

#include "FixedPoint.h"
#include "FunctionPointer.h"
#include "IntegralAP.h"
#include "MemberPointer.h"
Expand Down Expand Up @@ -190,6 +191,8 @@ class InterpStack final {
return PT_IntAP;
else if constexpr (std::is_same_v<T, MemberPointer>)
return PT_MemberPtr;
else if constexpr (std::is_same_v<T, FixedPoint>)
return PT_FixedPoint;

llvm_unreachable("unknown type push()'ed into InterpStack");
}
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/AST/ByteCode/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def Float : Type;
def Ptr : Type;
def FnPtr : Type;
def MemberPtr : Type;
def FixedPoint : Type;

//===----------------------------------------------------------------------===//
// Types transferred to the interpreter.
Expand All @@ -49,6 +50,7 @@ def ArgIntAP : ArgType { let Name = "IntegralAP<false>"; let AsRef = true; }
def ArgIntAPS : ArgType { let Name = "IntegralAP<true>"; let AsRef = true; }
def ArgFloat : ArgType { let Name = "Floating"; let AsRef = true; }
def ArgBool : ArgType { let Name = "bool"; }
def ArgFixedPoint : ArgType { let Name = "FixedPoint"; let AsRef = true; }

def ArgFunction : ArgType { let Name = "const Function *"; }
def ArgRecordDecl : ArgType { let Name = "const RecordDecl *"; }
Expand Down Expand Up @@ -108,7 +110,7 @@ def NonPtrTypeClass : TypeClass {
}

def AllTypeClass : TypeClass {
let Types = !listconcat(AluTypeClass.Types, PtrTypeClass.Types, FloatTypeClass.Types);
let Types = !listconcat(AluTypeClass.Types, PtrTypeClass.Types, FloatTypeClass.Types, [FixedPoint]);
}

def ComparableTypeClass : TypeClass {
Expand Down Expand Up @@ -255,6 +257,7 @@ def ConstFloat : ConstOpcode<Float, ArgFloat>;
def constIntAP : ConstOpcode<IntAP, ArgIntAP>;
def constIntAPS : ConstOpcode<IntAPS, ArgIntAPS>;
def ConstBool : ConstOpcode<Bool, ArgBool>;
def ConstFixedPoint : ConstOpcode<FixedPoint, ArgFixedPoint>;

// [] -> [Integer]
def Zero : Opcode {
Expand Down Expand Up @@ -607,7 +610,7 @@ def IsNonNull : Opcode {
//===----------------------------------------------------------------------===//

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

def ToCastTypeClass : TypeClass {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ByteCode/PrimType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "PrimType.h"
#include "Boolean.h"
#include "FixedPoint.h"
#include "Floating.h"
#include "FunctionPointer.h"
#include "IntegralAP.h"
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/ByteCode/PrimType.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class Boolean;
class Floating;
class FunctionPointer;
class MemberPointer;
class FixedPoint;
template <bool Signed> class IntegralAP;
template <unsigned Bits, bool Signed> class Integral;

Expand All @@ -46,6 +47,7 @@ enum PrimType : unsigned {
PT_Ptr = 12,
PT_FnPtr = 13,
PT_MemberPtr = 14,
PT_FixedPoint = 15,
};

inline constexpr bool isPtrType(PrimType T) {
Expand Down Expand Up @@ -118,6 +120,9 @@ template <> struct PrimConv<PT_FnPtr> {
template <> struct PrimConv<PT_MemberPtr> {
using T = MemberPointer;
};
template <> struct PrimConv<PT_FixedPoint> {
using T = FixedPoint;
};

/// Returns the size of a primitive type in bytes.
size_t primSize(PrimType Type);
Expand Down Expand Up @@ -163,6 +168,7 @@ static inline bool aligned(const void *P) {
TYPE_SWITCH_CASE(PT_Ptr, B) \
TYPE_SWITCH_CASE(PT_FnPtr, B) \
TYPE_SWITCH_CASE(PT_MemberPtr, B) \
TYPE_SWITCH_CASE(PT_FixedPoint, B) \
} \
} while (0)

Expand Down
9 changes: 9 additions & 0 deletions clang/test/AST/ByteCode/fixed-point.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: %clang_cc1 %s -fsyntax-only -ffixed-point -verify=expected,both -fexperimental-new-constant-interpreter
// RUN: %clang_cc1 %s -fsyntax-only -ffixed-point -verify=ref,both

static_assert((bool)1.0k);
static_assert(!((bool)0.0k));
static_assert((bool)0.0k); // both-error {{static assertion failed}}

static_assert(1.0k == 1.0k);
static_assert(1.0k != 1.0k); // both-error {{failed due to requirement '1.0k != 1.0k'}}
Loading