Skip to content

Commit

Permalink
[Clang] constexpr builtin floating point classification / compariso…
Browse files Browse the repository at this point in the history
…n functions (llvm#94118)

As per [P0533R9](https://wg21.link/P0533R9), the corresponding C++
`[c.math.fpclass]` standard library functions for the C macros are now
`constexpr`.

The only classification function that wasn't already `constexpr` was
`__builtin_signbit`.
The floating point comparison functions `__builtin_isgreater`,
`__builtin_isgreaterequal`, `__builtin_isless`, `__builtin_islessequal`,
`__builtin_islessgreater` and `__builtin_isunordered` are now
`constexpr`.
The C23 macro `iseqsig` is not currently supported because
`__bulitin_iseqsig` doesn't exist yet (and C++26 is still currently
based on C18).

This also allows them to be constant folded in C, matching the behaviour
of GCC.
  • Loading branch information
MitalAshok authored Aug 18, 2024
1 parent dac1829 commit 1125934
Show file tree
Hide file tree
Showing 6 changed files with 224 additions and 82 deletions.
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ C23 Feature Support
Non-comprehensive list of changes in this release
-------------------------------------------------

- The floating point comparison builtins (``__builtin_isgreater``,
``__builtin_isgreaterequal``, ``__builtin_isless``, etc.) and
``__builtin_signbit`` can now be used in constant expressions.

New Compiler Flags
------------------

Expand Down
20 changes: 11 additions & 9 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -533,42 +533,42 @@ def BuiltinComplex : Builtin {
def IsGreater : Builtin {
let Spellings = ["__builtin_isgreater"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const,
CustomTypeChecking];
CustomTypeChecking, Constexpr];
let Prototype = "int(...)";
}

def IsGreaterEqual : Builtin {
let Spellings = ["__builtin_isgreaterequal"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const,
CustomTypeChecking];
CustomTypeChecking, Constexpr];
let Prototype = "int(...)";
}

def IsLess : Builtin {
let Spellings = ["__builtin_isless"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const,
CustomTypeChecking];
CustomTypeChecking, Constexpr];
let Prototype = "int(...)";
}

def IsLessEqual : Builtin {
let Spellings = ["__builtin_islessequal"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const,
CustomTypeChecking];
CustomTypeChecking, Constexpr];
let Prototype = "int(...)";
}

def IsLessGreater : Builtin {
let Spellings = ["__builtin_islessgreater"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const,
CustomTypeChecking];
CustomTypeChecking, Constexpr];
let Prototype = "int(...)";
}

def IsUnordered : Builtin {
let Spellings = ["__builtin_isunordered"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const,
CustomTypeChecking];
CustomTypeChecking, Constexpr];
let Prototype = "int(...)";
}

Expand Down Expand Up @@ -646,19 +646,21 @@ def IsFPClass : Builtin {
def Signbit : Builtin {
let Spellings = ["__builtin_signbit"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const,
CustomTypeChecking];
CustomTypeChecking, Constexpr];
let Prototype = "int(...)";
}

def SignbitF : Builtin {
let Spellings = ["__builtin_signbitf"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const,
Constexpr];
let Prototype = "int(float)";
}

def SignbitL : Builtin {
let Spellings = ["__builtin_signbitl"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const,
Constexpr];
let Prototype = "int(long double)";
}

Expand Down
60 changes: 60 additions & 0 deletions clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,51 @@ static bool interp__builtin_iszero(InterpState &S, CodePtr OpPC,
return true;
}

static bool interp__builtin_signbit(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame, const Function *F,
const CallExpr *Call) {
const Floating &Arg = S.Stk.peek<Floating>();

pushInteger(S, Arg.isNegative(), Call->getType());
return true;
}

static bool interp_floating_comparison(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *F,
const CallExpr *Call) {
const Floating &RHS = S.Stk.peek<Floating>();
const Floating &LHS = S.Stk.peek<Floating>(align(2u * primSize(PT_Float)));
unsigned ID = F->getBuiltinID();

pushInteger(
S,
[&] {
switch (ID) {
case Builtin::BI__builtin_isgreater:
return LHS > RHS;
case Builtin::BI__builtin_isgreaterequal:
return LHS >= RHS;
case Builtin::BI__builtin_isless:
return LHS < RHS;
case Builtin::BI__builtin_islessequal:
return LHS <= RHS;
case Builtin::BI__builtin_islessgreater: {
ComparisonCategoryResult cmp = LHS.compare(RHS);
return cmp == ComparisonCategoryResult::Less ||
cmp == ComparisonCategoryResult::Greater;
}
case Builtin::BI__builtin_isunordered:
return LHS.compare(RHS) == ComparisonCategoryResult::Unordered;
default:
llvm_unreachable("Unexpected builtin ID: Should be a floating point "
"comparison function");
}
}(),
Call->getType());
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,
Expand Down Expand Up @@ -1313,6 +1358,21 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
if (!interp__builtin_iszero(S, OpPC, Frame, F, Call))
return false;
break;
case Builtin::BI__builtin_signbit:
case Builtin::BI__builtin_signbitf:
case Builtin::BI__builtin_signbitl:
if (!interp__builtin_signbit(S, OpPC, Frame, F, Call))
return false;
break;
case Builtin::BI__builtin_isgreater:
case Builtin::BI__builtin_isgreaterequal:
case Builtin::BI__builtin_isless:
case Builtin::BI__builtin_islessequal:
case Builtin::BI__builtin_islessgreater:
case Builtin::BI__builtin_isunordered:
if (!interp_floating_comparison(S, OpPC, Frame, F, Call))
return false;
break;
case Builtin::BI__builtin_isfpclass:
if (!interp__builtin_isfpclass(S, OpPC, Frame, F, Call))
return false;
Expand Down
48 changes: 48 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12833,6 +12833,54 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
Success(Val.isZero() ? 1 : 0, E);
}

case Builtin::BI__builtin_signbit:
case Builtin::BI__builtin_signbitf:
case Builtin::BI__builtin_signbitl: {
APFloat Val(0.0);
return EvaluateFloat(E->getArg(0), Val, Info) &&
Success(Val.isNegative() ? 1 : 0, E);
}

case Builtin::BI__builtin_isgreater:
case Builtin::BI__builtin_isgreaterequal:
case Builtin::BI__builtin_isless:
case Builtin::BI__builtin_islessequal:
case Builtin::BI__builtin_islessgreater:
case Builtin::BI__builtin_isunordered: {
APFloat LHS(0.0);
APFloat RHS(0.0);
if (!EvaluateFloat(E->getArg(0), LHS, Info) ||
!EvaluateFloat(E->getArg(1), RHS, Info))
return false;

return Success(
[&] {
switch (BuiltinOp) {
case Builtin::BI__builtin_isgreater:
return LHS > RHS;
case Builtin::BI__builtin_isgreaterequal:
return LHS >= RHS;
case Builtin::BI__builtin_isless:
return LHS < RHS;
case Builtin::BI__builtin_islessequal:
return LHS <= RHS;
case Builtin::BI__builtin_islessgreater: {
APFloat::cmpResult cmp = LHS.compare(RHS);
return cmp == APFloat::cmpResult::cmpLessThan ||
cmp == APFloat::cmpResult::cmpGreaterThan;
}
case Builtin::BI__builtin_isunordered:
return LHS.compare(RHS) == APFloat::cmpResult::cmpUnordered;
default:
llvm_unreachable("Unexpected builtin ID: Should be a floating "
"point comparison function");
}
}()
? 1
: 0,
E);
}

case Builtin::BI__builtin_issignaling: {
APFloat Val(0.0);
return EvaluateFloat(E->getArg(0), Val, Info) &&
Expand Down
126 changes: 53 additions & 73 deletions clang/test/Analysis/builtin_signbit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,103 +12,83 @@ long double ld = -1.0L;
// CHECK-BE32-LABEL: define dso_local void @_Z12test_signbitv(
// CHECK-BE32-SAME: ) #[[ATTR0:[0-9]+]] {
// CHECK-BE32-NEXT: entry:
// CHECK-BE32-NEXT: [[TMP0:%.*]] = lshr i128 bitcast (ppc_fp128 0xM3FF00000000000000000000000000000 to i128), 64
// CHECK-BE32-NEXT: [[TMP1:%.*]] = trunc i128 [[TMP0]] to i64
// CHECK-BE32-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP1]], 0
// CHECK-BE32-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP2]] to i8
// CHECK-BE32-NEXT: store i8 0, ptr @b, align 1
// CHECK-BE32-NEXT: [[TMP0:%.*]] = load ppc_fp128, ptr @ld, align 16
// CHECK-BE32-NEXT: [[TMP1:%.*]] = bitcast ppc_fp128 [[TMP0]] to i128
// CHECK-BE32-NEXT: [[TMP2:%.*]] = lshr i128 [[TMP1]], 64
// CHECK-BE32-NEXT: [[TMP3:%.*]] = trunc i128 [[TMP2]] to i64
// CHECK-BE32-NEXT: [[TMP4:%.*]] = icmp slt i64 [[TMP3]], 0
// CHECK-BE32-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP4]] to i8
// CHECK-BE32-NEXT: store i8 [[FROMBOOL]], ptr @b, align 1
// CHECK-BE32-NEXT: [[TMP3:%.*]] = load ppc_fp128, ptr @ld, align 16
// CHECK-BE32-NEXT: [[TMP4:%.*]] = bitcast ppc_fp128 [[TMP3]] to i128
// CHECK-BE32-NEXT: [[TMP5:%.*]] = lshr i128 [[TMP4]], 64
// CHECK-BE32-NEXT: [[TMP6:%.*]] = trunc i128 [[TMP5]] to i64
// CHECK-BE32-NEXT: [[TMP7:%.*]] = icmp slt i64 [[TMP6]], 0
// CHECK-BE32-NEXT: store i8 0, ptr @b, align 1
// CHECK-BE32-NEXT: [[TMP5:%.*]] = load double, ptr @d, align 8
// CHECK-BE32-NEXT: [[CONV:%.*]] = fptrunc double [[TMP5]] to float
// CHECK-BE32-NEXT: [[TMP6:%.*]] = bitcast float [[CONV]] to i32
// CHECK-BE32-NEXT: [[TMP7:%.*]] = icmp slt i32 [[TMP6]], 0
// CHECK-BE32-NEXT: [[FROMBOOL1:%.*]] = zext i1 [[TMP7]] to i8
// CHECK-BE32-NEXT: store i8 [[FROMBOOL1]], ptr @b, align 1
// CHECK-BE32-NEXT: store i8 0, ptr @b, align 1
// CHECK-BE32-NEXT: [[TMP8:%.*]] = load double, ptr @d, align 8
// CHECK-BE32-NEXT: [[CONV:%.*]] = fptrunc double [[TMP8]] to float
// CHECK-BE32-NEXT: [[TMP9:%.*]] = bitcast float [[CONV]] to i32
// CHECK-BE32-NEXT: [[TMP10:%.*]] = icmp slt i32 [[TMP9]], 0
// CHECK-BE32-NEXT: [[FROMBOOL2:%.*]] = zext i1 [[TMP10]] to i8
// CHECK-BE32-NEXT: [[TMP8:%.*]] = load ppc_fp128, ptr @ld, align 16
// CHECK-BE32-NEXT: [[TMP9:%.*]] = bitcast ppc_fp128 [[TMP8]] to i128
// CHECK-BE32-NEXT: [[TMP10:%.*]] = lshr i128 [[TMP9]], 64
// CHECK-BE32-NEXT: [[TMP11:%.*]] = trunc i128 [[TMP10]] to i64
// CHECK-BE32-NEXT: [[TMP12:%.*]] = icmp slt i64 [[TMP11]], 0
// CHECK-BE32-NEXT: [[FROMBOOL2:%.*]] = zext i1 [[TMP12]] to i8
// CHECK-BE32-NEXT: store i8 [[FROMBOOL2]], ptr @b, align 1
// CHECK-BE32-NEXT: [[TMP11:%.*]] = lshr i128 bitcast (ppc_fp128 0xM3FF00000000000000000000000000000 to i128), 64
// CHECK-BE32-NEXT: [[TMP12:%.*]] = trunc i128 [[TMP11]] to i64
// CHECK-BE32-NEXT: [[TMP13:%.*]] = icmp slt i64 [[TMP12]], 0
// CHECK-BE32-NEXT: [[FROMBOOL3:%.*]] = zext i1 [[TMP13]] to i8
// CHECK-BE32-NEXT: store i8 [[FROMBOOL3]], ptr @b, align 1
// CHECK-BE32-NEXT: [[TMP14:%.*]] = load ppc_fp128, ptr @ld, align 16
// CHECK-BE32-NEXT: [[TMP15:%.*]] = bitcast ppc_fp128 [[TMP14]] to i128
// CHECK-BE32-NEXT: [[TMP16:%.*]] = lshr i128 [[TMP15]], 64
// CHECK-BE32-NEXT: [[TMP17:%.*]] = trunc i128 [[TMP16]] to i64
// CHECK-BE32-NEXT: [[TMP18:%.*]] = icmp slt i64 [[TMP17]], 0
// CHECK-BE32-NEXT: [[FROMBOOL4:%.*]] = zext i1 [[TMP18]] to i8
// CHECK-BE32-NEXT: store i8 [[FROMBOOL4]], ptr @b, align 1
// CHECK-BE32-NEXT: ret void
//
// CHECK-BE64-LABEL: define dso_local void @_Z12test_signbitv(
// CHECK-BE64-SAME: ) #[[ATTR0:[0-9]+]] {
// CHECK-BE64-NEXT: entry:
// CHECK-BE64-NEXT: [[TMP0:%.*]] = lshr i128 bitcast (ppc_fp128 0xM3FF00000000000000000000000000000 to i128), 64
// CHECK-BE64-NEXT: [[TMP1:%.*]] = trunc i128 [[TMP0]] to i64
// CHECK-BE64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP1]], 0
// CHECK-BE64-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP2]] to i8
// CHECK-BE64-NEXT: store i8 0, ptr @b, align 1
// CHECK-BE64-NEXT: [[TMP0:%.*]] = load ppc_fp128, ptr @ld, align 16
// CHECK-BE64-NEXT: [[TMP1:%.*]] = bitcast ppc_fp128 [[TMP0]] to i128
// CHECK-BE64-NEXT: [[TMP2:%.*]] = lshr i128 [[TMP1]], 64
// CHECK-BE64-NEXT: [[TMP3:%.*]] = trunc i128 [[TMP2]] to i64
// CHECK-BE64-NEXT: [[TMP4:%.*]] = icmp slt i64 [[TMP3]], 0
// CHECK-BE64-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP4]] to i8
// CHECK-BE64-NEXT: store i8 [[FROMBOOL]], ptr @b, align 1
// CHECK-BE64-NEXT: [[TMP3:%.*]] = load ppc_fp128, ptr @ld, align 16
// CHECK-BE64-NEXT: [[TMP4:%.*]] = bitcast ppc_fp128 [[TMP3]] to i128
// CHECK-BE64-NEXT: [[TMP5:%.*]] = lshr i128 [[TMP4]], 64
// CHECK-BE64-NEXT: [[TMP6:%.*]] = trunc i128 [[TMP5]] to i64
// CHECK-BE64-NEXT: [[TMP7:%.*]] = icmp slt i64 [[TMP6]], 0
// CHECK-BE64-NEXT: store i8 0, ptr @b, align 1
// CHECK-BE64-NEXT: [[TMP5:%.*]] = load double, ptr @d, align 8
// CHECK-BE64-NEXT: [[CONV:%.*]] = fptrunc double [[TMP5]] to float
// CHECK-BE64-NEXT: [[TMP6:%.*]] = bitcast float [[CONV]] to i32
// CHECK-BE64-NEXT: [[TMP7:%.*]] = icmp slt i32 [[TMP6]], 0
// CHECK-BE64-NEXT: [[FROMBOOL1:%.*]] = zext i1 [[TMP7]] to i8
// CHECK-BE64-NEXT: store i8 [[FROMBOOL1]], ptr @b, align 1
// CHECK-BE64-NEXT: store i8 0, ptr @b, align 1
// CHECK-BE64-NEXT: [[TMP8:%.*]] = load double, ptr @d, align 8
// CHECK-BE64-NEXT: [[CONV:%.*]] = fptrunc double [[TMP8]] to float
// CHECK-BE64-NEXT: [[TMP9:%.*]] = bitcast float [[CONV]] to i32
// CHECK-BE64-NEXT: [[TMP10:%.*]] = icmp slt i32 [[TMP9]], 0
// CHECK-BE64-NEXT: [[FROMBOOL2:%.*]] = zext i1 [[TMP10]] to i8
// CHECK-BE64-NEXT: [[TMP8:%.*]] = load ppc_fp128, ptr @ld, align 16
// CHECK-BE64-NEXT: [[TMP9:%.*]] = bitcast ppc_fp128 [[TMP8]] to i128
// CHECK-BE64-NEXT: [[TMP10:%.*]] = lshr i128 [[TMP9]], 64
// CHECK-BE64-NEXT: [[TMP11:%.*]] = trunc i128 [[TMP10]] to i64
// CHECK-BE64-NEXT: [[TMP12:%.*]] = icmp slt i64 [[TMP11]], 0
// CHECK-BE64-NEXT: [[FROMBOOL2:%.*]] = zext i1 [[TMP12]] to i8
// CHECK-BE64-NEXT: store i8 [[FROMBOOL2]], ptr @b, align 1
// CHECK-BE64-NEXT: [[TMP11:%.*]] = lshr i128 bitcast (ppc_fp128 0xM3FF00000000000000000000000000000 to i128), 64
// CHECK-BE64-NEXT: [[TMP12:%.*]] = trunc i128 [[TMP11]] to i64
// CHECK-BE64-NEXT: [[TMP13:%.*]] = icmp slt i64 [[TMP12]], 0
// CHECK-BE64-NEXT: [[FROMBOOL3:%.*]] = zext i1 [[TMP13]] to i8
// CHECK-BE64-NEXT: store i8 [[FROMBOOL3]], ptr @b, align 1
// CHECK-BE64-NEXT: [[TMP14:%.*]] = load ppc_fp128, ptr @ld, align 16
// CHECK-BE64-NEXT: [[TMP15:%.*]] = bitcast ppc_fp128 [[TMP14]] to i128
// CHECK-BE64-NEXT: [[TMP16:%.*]] = lshr i128 [[TMP15]], 64
// CHECK-BE64-NEXT: [[TMP17:%.*]] = trunc i128 [[TMP16]] to i64
// CHECK-BE64-NEXT: [[TMP18:%.*]] = icmp slt i64 [[TMP17]], 0
// CHECK-BE64-NEXT: [[FROMBOOL4:%.*]] = zext i1 [[TMP18]] to i8
// CHECK-BE64-NEXT: store i8 [[FROMBOOL4]], ptr @b, align 1
// CHECK-BE64-NEXT: ret void
//
// CHECK-LE-LABEL: define dso_local void @_Z12test_signbitv(
// CHECK-LE-SAME: ) #[[ATTR0:[0-9]+]] {
// CHECK-LE-NEXT: entry:
// CHECK-LE-NEXT: [[TMP0:%.*]] = icmp slt i64 trunc (i128 bitcast (ppc_fp128 0xM3FF00000000000000000000000000000 to i128) to i64), 0
// CHECK-LE-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP0]] to i8
// CHECK-LE-NEXT: store i8 0, ptr @b, align 1
// CHECK-LE-NEXT: [[TMP0:%.*]] = load ppc_fp128, ptr @ld, align 16
// CHECK-LE-NEXT: [[TMP1:%.*]] = bitcast ppc_fp128 [[TMP0]] to i128
// CHECK-LE-NEXT: [[TMP2:%.*]] = trunc i128 [[TMP1]] to i64
// CHECK-LE-NEXT: [[TMP3:%.*]] = icmp slt i64 [[TMP2]], 0
// CHECK-LE-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP3]] to i8
// CHECK-LE-NEXT: store i8 [[FROMBOOL]], ptr @b, align 1
// CHECK-LE-NEXT: [[TMP1:%.*]] = load ppc_fp128, ptr @ld, align 16
// CHECK-LE-NEXT: [[TMP2:%.*]] = bitcast ppc_fp128 [[TMP1]] to i128
// CHECK-LE-NEXT: [[TMP3:%.*]] = trunc i128 [[TMP2]] to i64
// CHECK-LE-NEXT: [[TMP4:%.*]] = icmp slt i64 [[TMP3]], 0
// CHECK-LE-NEXT: [[FROMBOOL1:%.*]] = zext i1 [[TMP4]] to i8
// CHECK-LE-NEXT: store i8 0, ptr @b, align 1
// CHECK-LE-NEXT: [[TMP4:%.*]] = load double, ptr @d, align 8
// CHECK-LE-NEXT: [[CONV:%.*]] = fptrunc double [[TMP4]] to float
// CHECK-LE-NEXT: [[TMP5:%.*]] = bitcast float [[CONV]] to i32
// CHECK-LE-NEXT: [[TMP6:%.*]] = icmp slt i32 [[TMP5]], 0
// CHECK-LE-NEXT: [[FROMBOOL1:%.*]] = zext i1 [[TMP6]] to i8
// CHECK-LE-NEXT: store i8 [[FROMBOOL1]], ptr @b, align 1
// CHECK-LE-NEXT: store i8 0, ptr @b, align 1
// CHECK-LE-NEXT: [[TMP5:%.*]] = load double, ptr @d, align 8
// CHECK-LE-NEXT: [[CONV:%.*]] = fptrunc double [[TMP5]] to float
// CHECK-LE-NEXT: [[TMP6:%.*]] = bitcast float [[CONV]] to i32
// CHECK-LE-NEXT: [[TMP7:%.*]] = icmp slt i32 [[TMP6]], 0
// CHECK-LE-NEXT: [[FROMBOOL2:%.*]] = zext i1 [[TMP7]] to i8
// CHECK-LE-NEXT: [[TMP7:%.*]] = load ppc_fp128, ptr @ld, align 16
// CHECK-LE-NEXT: [[TMP8:%.*]] = bitcast ppc_fp128 [[TMP7]] to i128
// CHECK-LE-NEXT: [[TMP9:%.*]] = trunc i128 [[TMP8]] to i64
// CHECK-LE-NEXT: [[TMP10:%.*]] = icmp slt i64 [[TMP9]], 0
// CHECK-LE-NEXT: [[FROMBOOL2:%.*]] = zext i1 [[TMP10]] to i8
// CHECK-LE-NEXT: store i8 [[FROMBOOL2]], ptr @b, align 1
// CHECK-LE-NEXT: [[TMP8:%.*]] = icmp slt i64 trunc (i128 bitcast (ppc_fp128 0xM3FF00000000000000000000000000000 to i128) to i64), 0
// CHECK-LE-NEXT: [[FROMBOOL3:%.*]] = zext i1 [[TMP8]] to i8
// CHECK-LE-NEXT: store i8 [[FROMBOOL3]], ptr @b, align 1
// CHECK-LE-NEXT: [[TMP9:%.*]] = load ppc_fp128, ptr @ld, align 16
// CHECK-LE-NEXT: [[TMP10:%.*]] = bitcast ppc_fp128 [[TMP9]] to i128
// CHECK-LE-NEXT: [[TMP11:%.*]] = trunc i128 [[TMP10]] to i64
// CHECK-LE-NEXT: [[TMP12:%.*]] = icmp slt i64 [[TMP11]], 0
// CHECK-LE-NEXT: [[FROMBOOL4:%.*]] = zext i1 [[TMP12]] to i8
// CHECK-LE-NEXT: store i8 [[FROMBOOL4]], ptr @b, align 1
// CHECK-LE-NEXT: ret void
//
void test_signbit()
Expand Down
Loading

0 comments on commit 1125934

Please sign in to comment.