Skip to content

Commit

Permalink
[clang][Interp] Implement __builtin_isfpclass
Browse files Browse the repository at this point in the history
  • Loading branch information
tbaederr committed Aug 1, 2023
1 parent d3718f1 commit 6ba4b21
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 0 deletions.
1 change: 1 addition & 0 deletions clang/lib/AST/Interp/Floating.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class Floating final {
bool isInf() const { return F.isInfinity(); }
bool isFinite() const { return F.isFinite(); }
bool isNormal() const { return F.isNormal(); }
llvm::FPClassTest classify() const { return F.classify(); }

ComparisonCategoryResult compare(const Floating &RHS) const {
llvm::APFloatBase::cmpResult CmpRes = F.compare(RHS.F);
Expand Down
34 changes: 34 additions & 0 deletions clang/lib/AST/Interp/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ static T getParam(const InterpFrame *Frame, unsigned Index) {
return Frame->getParam<T>(Offset);
}

/// Peek an integer value from the stack into an APSInt.
static APSInt peekToAPSInt(InterpStack &Stk, PrimType T) {
APSInt R;
INT_TYPE_SWITCH(T, {
T Val = Stk.peek<T>();
R = APSInt(APInt(T::bitWidth(), static_cast<uint64_t>(Val), T::isSigned()));
});

return R;
}

static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame) {
const Pointer &A = getParam<Pointer>(Frame, 0);
Expand Down Expand Up @@ -205,6 +216,25 @@ static bool interp__builtin_isnormal(InterpState &S, CodePtr OpPC,
return true;
}

/// First parameter to __builtin_isfpclass is the floating value, the
/// second one is an integral value.
static bool interp__builtin_isfpclass(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func) {
const Expr *E = S.Current->getExpr(OpPC);
const CallExpr *CE = cast<CallExpr>(E);
PrimType FPClassArgT = *S.getContext().classify(CE->getArgs()[1]->getType());
APSInt FPClassArg = peekToAPSInt(S.Stk, FPClassArgT);
const Floating &F =
S.Stk.peek<Floating>(align(primSize(FPClassArgT) + primSize(PT_Float)));

int32_t Result =
static_cast<int32_t>((F.classify() & FPClassArg).getZExtValue());
S.Stk.push<Integral<32, true>>(Integral<32, true>::from(Result));

return true;
}

bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F) {
InterpFrame *Frame = S.Current;
APValue Dummy;
Expand Down Expand Up @@ -289,6 +319,10 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F) {
if (interp__builtin_isnormal(S, OpPC, Frame, F))
return Ret<PT_Sint32>(S, OpPC, Dummy);
break;
case Builtin::BI__builtin_isfpclass:
if (interp__builtin_isfpclass(S, OpPC, Frame, F))
return Ret<PT_Sint32>(S, OpPC, Dummy);
break;

default:
return false;
Expand Down
18 changes: 18 additions & 0 deletions clang/lib/AST/Interp/PrimType.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,24 @@ static inline bool aligned(const void *P) {
TYPE_SWITCH_CASE(PT_FnPtr, B) \
} \
} while (0)

#define INT_TYPE_SWITCH(Expr, B) \
do { \
switch (Expr) { \
TYPE_SWITCH_CASE(PT_Sint8, B) \
TYPE_SWITCH_CASE(PT_Uint8, B) \
TYPE_SWITCH_CASE(PT_Sint16, B) \
TYPE_SWITCH_CASE(PT_Uint16, B) \
TYPE_SWITCH_CASE(PT_Sint32, B) \
TYPE_SWITCH_CASE(PT_Uint32, B) \
TYPE_SWITCH_CASE(PT_Sint64, B) \
TYPE_SWITCH_CASE(PT_Uint64, B) \
TYPE_SWITCH_CASE(PT_Bool, B) \
default: \
llvm_unreachable("Not an integer value"); \
} \
} while (0)

#define COMPOSITE_TYPE_SWITCH(Expr, B, D) \
do { \
switch (Expr) { \
Expand Down
43 changes: 43 additions & 0 deletions clang/test/AST/Interp/builtin-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,46 @@ namespace inf {
static_assert(__builtin_isnormal(1.0), "");
static_assert(!__builtin_isnormal(__builtin_inf()), "");
}

namespace isfpclass {
char isfpclass_inf_pos_0[__builtin_isfpclass(__builtin_inf(), 0x0200) ? 1 : -1]; // fcPosInf
char isfpclass_inf_pos_1[!__builtin_isfpclass(__builtin_inff(), 0x0004) ? 1 : -1]; // fcNegInf
char isfpclass_inf_pos_2[__builtin_isfpclass(__builtin_infl(), 0x0207) ? 1 : -1]; // fcSNan|fcQNan|fcNegInf|fcPosInf
char isfpclass_inf_pos_3[!__builtin_isfpclass(__builtin_inf(), 0x01F8) ? 1 : -1]; // fcFinite
char isfpclass_pos_0 [__builtin_isfpclass(1.0, 0x0100) ? 1 : -1]; // fcPosNormal
char isfpclass_pos_1 [!__builtin_isfpclass(1.0f, 0x0008) ? 1 : -1]; // fcNegNormal
char isfpclass_pos_2 [__builtin_isfpclass(1.0L, 0x01F8) ? 1 : -1]; // fcFinite
char isfpclass_pos_3 [!__builtin_isfpclass(1.0, 0x0003) ? 1 : -1]; // fcSNan|fcQNan
char isfpclass_pdenorm_0[__builtin_isfpclass(1.0e-40f, 0x0080) ? 1 : -1]; // fcPosSubnormal
char isfpclass_pdenorm_1[__builtin_isfpclass(1.0e-310, 0x01F8) ? 1 : -1]; // fcFinite
char isfpclass_pdenorm_2[!__builtin_isfpclass(1.0e-40f, 0x003C) ? 1 : -1]; // fcNegative
char isfpclass_pdenorm_3[!__builtin_isfpclass(1.0e-310, 0x0207) ? 1 : -1]; // ~fcFinite
char isfpclass_pzero_0 [__builtin_isfpclass(0.0f, 0x0060) ? 1 : -1]; // fcZero
char isfpclass_pzero_1 [__builtin_isfpclass(0.0, 0x01F8) ? 1 : -1]; // fcFinite
char isfpclass_pzero_2 [!__builtin_isfpclass(0.0L, 0x0020) ? 1 : -1]; // fcNegZero
char isfpclass_pzero_3 [!__builtin_isfpclass(0.0, 0x0003) ? 1 : -1]; // fcNan
char isfpclass_nzero_0 [__builtin_isfpclass(-0.0f, 0x0060) ? 1 : -1]; // fcZero
char isfpclass_nzero_1 [__builtin_isfpclass(-0.0, 0x01F8) ? 1 : -1]; // fcFinite
char isfpclass_nzero_2 [!__builtin_isfpclass(-0.0L, 0x0040) ? 1 : -1]; // fcPosZero
char isfpclass_nzero_3 [!__builtin_isfpclass(-0.0, 0x0003) ? 1 : -1]; // fcNan
char isfpclass_ndenorm_0[__builtin_isfpclass(-1.0e-40f, 0x0010) ? 1 : -1]; // fcNegSubnormal
char isfpclass_ndenorm_1[__builtin_isfpclass(-1.0e-310, 0x01F8) ? 1 : -1]; // fcFinite
char isfpclass_ndenorm_2[!__builtin_isfpclass(-1.0e-40f, 0x03C0) ? 1 : -1]; // fcPositive
char isfpclass_ndenorm_3[!__builtin_isfpclass(-1.0e-310, 0x0207) ? 1 : -1]; // ~fcFinite
char isfpclass_neg_0 [__builtin_isfpclass(-1.0, 0x0008) ? 1 : -1]; // fcNegNormal
char isfpclass_neg_1 [!__builtin_isfpclass(-1.0f, 0x00100) ? 1 : -1]; // fcPosNormal
char isfpclass_neg_2 [__builtin_isfpclass(-1.0L, 0x01F8) ? 1 : -1]; // fcFinite
char isfpclass_neg_3 [!__builtin_isfpclass(-1.0, 0x0003) ? 1 : -1]; // fcSNan|fcQNan
char isfpclass_inf_neg_0[__builtin_isfpclass(-__builtin_inf(), 0x0004) ? 1 : -1]; // fcNegInf
char isfpclass_inf_neg_1[!__builtin_isfpclass(-__builtin_inff(), 0x0200) ? 1 : -1]; // fcPosInf
char isfpclass_inf_neg_2[__builtin_isfpclass(-__builtin_infl(), 0x0207) ? 1 : -1]; // ~fcFinite
char isfpclass_inf_neg_3[!__builtin_isfpclass(-__builtin_inf(), 0x03C0) ? 1 : -1]; // fcPositive
char isfpclass_qnan_0 [__builtin_isfpclass(__builtin_nan(""), 0x0002) ? 1 : -1]; // fcQNan
char isfpclass_qnan_1 [!__builtin_isfpclass(__builtin_nanf(""), 0x0001) ? 1 : -1]; // fcSNan
char isfpclass_qnan_2 [__builtin_isfpclass(__builtin_nanl(""), 0x0207) ? 1 : -1]; // ~fcFinite
char isfpclass_qnan_3 [!__builtin_isfpclass(__builtin_nan(""), 0x01F8) ? 1 : -1]; // fcFinite
char isfpclass_snan_0 [__builtin_isfpclass(__builtin_nansf(""), 0x0001) ? 1 : -1]; // fcSNan
char isfpclass_snan_1 [!__builtin_isfpclass(__builtin_nans(""), 0x0002) ? 1 : -1]; // fcQNan
char isfpclass_snan_2 [__builtin_isfpclass(__builtin_nansl(""), 0x0207) ? 1 : -1]; // ~fcFinite
char isfpclass_snan_3 [!__builtin_isfpclass(__builtin_nans(""), 0x01F8) ? 1 : -1]; // fcFinite
}

0 comments on commit 6ba4b21

Please sign in to comment.