Skip to content

Commit 95ce78b

Browse files
authored
[clang][bytecode] Implement fixed-point-to-int casts (#110417)
And some cleanups around overflow handling.
1 parent 1edd220 commit 95ce78b

File tree

9 files changed

+106
-67
lines changed

9 files changed

+106
-67
lines changed

clang/lib/AST/ByteCode/Boolean.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class Boolean final {
3030
public:
3131
/// Zero-initializes a boolean.
3232
Boolean() : V(false) {}
33+
Boolean(const llvm::APSInt &I) : V(!I.isZero()) {}
3334
explicit Boolean(bool V) : V(V) {}
3435

3536
bool operator<(Boolean RHS) const { return V < RHS.V; }

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,11 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
697697
const auto *TargetSemantics = &Ctx.getFloatSemantics(CE->getType());
698698
return this->emitCastFixedPointFloating(TargetSemantics, CE);
699699
}
700+
case CK_FixedPointToIntegral: {
701+
if (!this->visit(SubExpr))
702+
return false;
703+
return this->emitCastFixedPointIntegral(classifyPrim(CE->getType()), CE);
704+
}
700705
case CK_FixedPointCast: {
701706
if (!this->visit(SubExpr))
702707
return false;
@@ -1562,6 +1567,25 @@ bool Compiler<Emitter>::VisitFixedPointBinOp(const BinaryOperator *E) {
15621567
llvm_unreachable("unhandled binop opcode");
15631568
}
15641569

1570+
template <class Emitter>
1571+
bool Compiler<Emitter>::VisitFixedPointUnaryOperator(const UnaryOperator *E) {
1572+
const Expr *SubExpr = E->getSubExpr();
1573+
assert(SubExpr->getType()->isFixedPointType());
1574+
1575+
switch (E->getOpcode()) {
1576+
case UO_Plus:
1577+
return this->delegate(SubExpr);
1578+
case UO_Minus:
1579+
if (!this->visit(SubExpr))
1580+
return false;
1581+
return this->emitNegFixedPoint(E);
1582+
default:
1583+
return false;
1584+
}
1585+
1586+
llvm_unreachable("Unhandled unary opcode");
1587+
}
1588+
15651589
template <class Emitter>
15661590
bool Compiler<Emitter>::VisitImplicitValueInitExpr(
15671591
const ImplicitValueInitExpr *E) {
@@ -3805,7 +3829,7 @@ bool Compiler<Emitter>::visitZeroInitializer(PrimType T, QualType QT,
38053829
return this->emitConstFloat(APFloat::getZero(Ctx.getFloatSemantics(QT)), E);
38063830
case PT_FixedPoint: {
38073831
auto Sem = Ctx.getASTContext().getFixedPointSemantics(E->getType());
3808-
return this->emitConstFixedPoint(FixedPoint::Zero(Sem), E);
3832+
return this->emitConstFixedPoint(FixedPoint::zero(Sem), E);
38093833
}
38103834
llvm_unreachable("Implement");
38113835
}
@@ -5471,6 +5495,8 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
54715495
return this->VisitComplexUnaryOperator(E);
54725496
if (SubExpr->getType()->isVectorType())
54735497
return this->VisitVectorUnaryOperator(E);
5498+
if (SubExpr->getType()->isFixedPointType())
5499+
return this->VisitFixedPointUnaryOperator(E);
54745500
std::optional<PrimType> T = classify(SubExpr->getType());
54755501

54765502
switch (E->getOpcode()) {

clang/lib/AST/ByteCode/Compiler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
133133
bool VisitComplexBinOp(const BinaryOperator *E);
134134
bool VisitVectorBinOp(const BinaryOperator *E);
135135
bool VisitFixedPointBinOp(const BinaryOperator *E);
136+
bool VisitFixedPointUnaryOperator(const UnaryOperator *E);
136137
bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);
137138
bool VisitCallExpr(const CallExpr *E);
138139
bool VisitBuiltinCallExpr(const CallExpr *E, unsigned BuiltinID);

clang/lib/AST/ByteCode/FixedPoint.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,20 @@ class FixedPoint final {
3333
: V(APInt(0, 0ULL, false),
3434
llvm::FixedPointSemantics(0, 0, false, false, false)) {}
3535

36-
static FixedPoint Zero(llvm::FixedPointSemantics Sem) {
36+
static FixedPoint zero(llvm::FixedPointSemantics Sem) {
3737
return FixedPoint(APInt(Sem.getWidth(), 0ULL, Sem.isSigned()), Sem);
3838
}
3939

40-
operator bool() const { return V.getBoolValue(); }
41-
template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>
42-
explicit operator Ty() const {
43-
// FIXME
44-
return 0;
40+
static FixedPoint from(const APSInt &I, llvm::FixedPointSemantics Sem,
41+
bool *Overflow) {
42+
return FixedPoint(llvm::APFixedPoint::getFromIntValue(I, Sem, Overflow));
43+
}
44+
static FixedPoint from(const llvm::APFloat &I, llvm::FixedPointSemantics Sem,
45+
bool *Overflow) {
46+
return FixedPoint(llvm::APFixedPoint::getFromFloatValue(I, Sem, Overflow));
4547
}
4648

49+
operator bool() const { return V.getBoolValue(); }
4750
void print(llvm::raw_ostream &OS) const { OS << V; }
4851

4952
APValue toAPValue(const ASTContext &) const { return APValue(V); }
@@ -70,6 +73,10 @@ class FixedPoint final {
7073
return V.convertToFloat(*Sem);
7174
}
7275

76+
llvm::APSInt toInt(unsigned BitWidth, bool Signed, bool *Overflow) const {
77+
return V.convertToInt(BitWidth, Signed, Overflow);
78+
}
79+
7380
std::string toDiagnosticString(const ASTContext &Ctx) const {
7481
return V.toString();
7582
}

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1393,6 +1393,19 @@ bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E) {
13931393
return false;
13941394
}
13951395

1396+
bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC,
1397+
const FixedPoint &FP) {
1398+
const Expr *E = S.Current->getExpr(OpPC);
1399+
if (S.checkingForUndefinedBehavior()) {
1400+
S.getASTContext().getDiagnostics().Report(
1401+
E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
1402+
<< FP.toDiagnosticString(S.getASTContext()) << E->getType();
1403+
}
1404+
S.CCEDiag(E, diag::note_constexpr_overflow)
1405+
<< FP.toDiagnosticString(S.getASTContext()) << E->getType();
1406+
return S.noteUndefinedBehavior();
1407+
}
1408+
13961409
bool Interpret(InterpState &S, APValue &Result) {
13971410
// The current stack frame when we started Interpret().
13981411
// This is being used by the ops to determine wheter

clang/lib/AST/ByteCode/Interp.h

Lines changed: 38 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,15 @@ bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
162162
const CallExpr *CE);
163163
bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T);
164164

165+
template <typename T>
166+
static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) {
167+
const Expr *E = S.Current->getExpr(OpPC);
168+
S.CCEDiag(E, diag::note_constexpr_overflow) << SrcValue << E->getType();
169+
return S.noteUndefinedBehavior();
170+
}
171+
bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC,
172+
const FixedPoint &FP);
173+
165174
enum class ShiftDir { Left, Right };
166175

167176
/// Checks if the shift operation is legal.
@@ -385,13 +394,10 @@ bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
385394
<< Trunc << Type << E->getSourceRange();
386395
}
387396

388-
S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
389-
390-
if (!S.noteUndefinedBehavior()) {
397+
if (!handleOverflow(S, OpPC, Value)) {
391398
S.Stk.pop<T>();
392399
return false;
393400
}
394-
395401
return true;
396402
}
397403

@@ -741,8 +747,7 @@ bool Neg(InterpState &S, CodePtr OpPC) {
741747
return true;
742748
}
743749

744-
S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue << Type;
745-
return S.noteUndefinedBehavior();
750+
return handleOverflow(S, OpPC, NegatedValue);
746751
}
747752

748753
enum class PushVal : bool {
@@ -804,8 +809,7 @@ bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
804809
return true;
805810
}
806811

807-
S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
808-
return S.noteUndefinedBehavior();
812+
return handleOverflow(S, OpPC, APResult);
809813
}
810814

811815
/// 1) Pops a pointer from the stack
@@ -2170,18 +2174,8 @@ inline bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS) {
21702174
bool Overflow;
21712175
FixedPoint Result = Source.toSemantics(TargetSemantics, &Overflow);
21722176

2173-
if (Overflow) {
2174-
const Expr *E = S.Current->getExpr(OpPC);
2175-
if (S.checkingForUndefinedBehavior()) {
2176-
S.getASTContext().getDiagnostics().Report(
2177-
E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
2178-
<< Result.toDiagnosticString(S.getASTContext()) << E->getType();
2179-
}
2180-
S.CCEDiag(E, diag::note_constexpr_overflow)
2181-
<< Result.toDiagnosticString(S.getASTContext()) << E->getType();
2182-
if (!S.noteUndefinedBehavior())
2183-
return false;
2184-
}
2177+
if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
2178+
return false;
21852179

21862180
S.Stk.push<FixedPoint>(Result);
21872181
return true;
@@ -2257,13 +2251,8 @@ static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
22572251
auto Status = F.convertToInteger(Result);
22582252

22592253
// Float-to-Integral overflow check.
2260-
if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
2261-
const Expr *E = S.Current->getExpr(OpPC);
2262-
QualType Type = E->getType();
2263-
2264-
S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2265-
return S.noteUndefinedBehavior();
2266-
}
2254+
if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())
2255+
return handleOverflow(S, OpPC, F.getAPFloat());
22672256

22682257
FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
22692258
S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
@@ -2278,13 +2267,8 @@ static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
22782267
auto Status = F.convertToInteger(Result);
22792268

22802269
// Float-to-Integral overflow check.
2281-
if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
2282-
const Expr *E = S.Current->getExpr(OpPC);
2283-
QualType Type = E->getType();
2284-
2285-
S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2286-
return S.noteUndefinedBehavior();
2287-
}
2270+
if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())
2271+
return handleOverflow(S, OpPC, F.getAPFloat());
22882272

22892273
FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
22902274
S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
@@ -2347,20 +2331,10 @@ static inline bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC,
23472331
std::memcpy(&Sem, &FPS, sizeof(Sem));
23482332

23492333
bool Overflow;
2350-
llvm::APFixedPoint Result =
2351-
llvm::APFixedPoint::getFromIntValue(Int.toAPSInt(), Sem, &Overflow);
2334+
FixedPoint Result = FixedPoint::from(Int.toAPSInt(), Sem, &Overflow);
23522335

2353-
if (Overflow) {
2354-
const Expr *E = S.Current->getExpr(OpPC);
2355-
if (S.checkingForUndefinedBehavior()) {
2356-
S.getASTContext().getDiagnostics().Report(
2357-
E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
2358-
<< Result.toString() << E->getType();
2359-
}
2360-
S.CCEDiag(E, diag::note_constexpr_overflow) << Result << E->getType();
2361-
if (!S.noteUndefinedBehavior())
2362-
return false;
2363-
}
2336+
if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
2337+
return false;
23642338

23652339
S.Stk.push<FixedPoint>(Result);
23662340
return true;
@@ -2374,20 +2348,10 @@ static inline bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC,
23742348
std::memcpy(&Sem, &FPS, sizeof(Sem));
23752349

23762350
bool Overflow;
2377-
llvm::APFixedPoint Result =
2378-
llvm::APFixedPoint::getFromFloatValue(Float.getAPFloat(), Sem, &Overflow);
2351+
FixedPoint Result = FixedPoint::from(Float.getAPFloat(), Sem, &Overflow);
23792352

2380-
if (Overflow) {
2381-
const Expr *E = S.Current->getExpr(OpPC);
2382-
if (S.checkingForUndefinedBehavior()) {
2383-
S.getASTContext().getDiagnostics().Report(
2384-
E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
2385-
<< Result.toString() << E->getType();
2386-
}
2387-
S.CCEDiag(E, diag::note_constexpr_overflow) << Result << E->getType();
2388-
if (!S.noteUndefinedBehavior())
2389-
return false;
2390-
}
2353+
if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
2354+
return false;
23912355

23922356
S.Stk.push<FixedPoint>(Result);
23932357
return true;
@@ -2401,6 +2365,20 @@ static inline bool CastFixedPointFloating(InterpState &S, CodePtr OpPC,
24012365
return true;
24022366
}
24032367

2368+
template <PrimType Name, class T = typename PrimConv<Name>::T>
2369+
static inline bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC) {
2370+
const auto &Fixed = S.Stk.pop<FixedPoint>();
2371+
2372+
bool Overflow;
2373+
APSInt Int = Fixed.toInt(T::bitWidth(), T::isSigned(), &Overflow);
2374+
2375+
if (Overflow && !handleOverflow(S, OpPC, Int))
2376+
return false;
2377+
2378+
S.Stk.push<T>(Int);
2379+
return true;
2380+
}
2381+
24042382
static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {
24052383
const auto &Ptr = S.Stk.peek<Pointer>();
24062384

clang/lib/AST/ByteCode/Opcodes.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,10 @@ def CastFloatingFixedPoint : Opcode {
689689
def CastFixedPointFloating : Opcode {
690690
let Args = [ArgFltSemantics];
691691
}
692+
def CastFixedPointIntegral : Opcode {
693+
let Types = [FixedSizeIntegralTypes];
694+
let HasGroup = 1;
695+
}
692696

693697
def PtrPtrCast : Opcode {
694698
let Args = [ArgBool];

clang/test/AST/ByteCode/fixed-point.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ namespace IntToFixedPointCast {
2626
static_assert(sf == -1);
2727
}
2828

29+
namespace FixedPointToIntCasts {
30+
constexpr _Accum A = -13.0k;
31+
constexpr int I = A;
32+
static_assert(I == -13);
33+
}
34+
2935
namespace FloatToFixedPointCast {
3036
constexpr _Fract sf = 1.0; // both-error {{must be initialized by a constant expression}} \
3137
// both-note {{outside the range of representable values of type 'const _Fract'}}

clang/test/Frontend/fixed_point_conversions_const.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,SIGNED
22
// RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - -fpadding-on-unsigned-fixed-point | FileCheck %s --check-prefixes=CHECK,UNSIGNED
33

4+
// RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - -fexperimental-new-constant-interpreter | FileCheck %s --check-prefixes=CHECK,SIGNED
5+
// RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - -fpadding-on-unsigned-fixed-point -fexperimental-new-constant-interpreter | FileCheck %s --check-prefixes=CHECK,UNSIGNED
6+
47
// Between different fixed point types
58
short _Accum sa_const = 2.5hk;
69
// CHECK-DAG: @sa_const = {{.*}}global i16 320, align 2

0 commit comments

Comments
 (0)