Skip to content

Commit 1125934

Browse files
authored
[Clang] constexpr builtin floating point classification / comparison functions (#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.
1 parent dac1829 commit 1125934

File tree

6 files changed

+224
-82
lines changed

6 files changed

+224
-82
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,10 @@ C23 Feature Support
161161
Non-comprehensive list of changes in this release
162162
-------------------------------------------------
163163

164+
- The floating point comparison builtins (``__builtin_isgreater``,
165+
``__builtin_isgreaterequal``, ``__builtin_isless``, etc.) and
166+
``__builtin_signbit`` can now be used in constant expressions.
167+
164168
New Compiler Flags
165169
------------------
166170

clang/include/clang/Basic/Builtins.td

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -533,42 +533,42 @@ def BuiltinComplex : Builtin {
533533
def IsGreater : Builtin {
534534
let Spellings = ["__builtin_isgreater"];
535535
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const,
536-
CustomTypeChecking];
536+
CustomTypeChecking, Constexpr];
537537
let Prototype = "int(...)";
538538
}
539539

540540
def IsGreaterEqual : Builtin {
541541
let Spellings = ["__builtin_isgreaterequal"];
542542
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const,
543-
CustomTypeChecking];
543+
CustomTypeChecking, Constexpr];
544544
let Prototype = "int(...)";
545545
}
546546

547547
def IsLess : Builtin {
548548
let Spellings = ["__builtin_isless"];
549549
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const,
550-
CustomTypeChecking];
550+
CustomTypeChecking, Constexpr];
551551
let Prototype = "int(...)";
552552
}
553553

554554
def IsLessEqual : Builtin {
555555
let Spellings = ["__builtin_islessequal"];
556556
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const,
557-
CustomTypeChecking];
557+
CustomTypeChecking, Constexpr];
558558
let Prototype = "int(...)";
559559
}
560560

561561
def IsLessGreater : Builtin {
562562
let Spellings = ["__builtin_islessgreater"];
563563
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const,
564-
CustomTypeChecking];
564+
CustomTypeChecking, Constexpr];
565565
let Prototype = "int(...)";
566566
}
567567

568568
def IsUnordered : Builtin {
569569
let Spellings = ["__builtin_isunordered"];
570570
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const,
571-
CustomTypeChecking];
571+
CustomTypeChecking, Constexpr];
572572
let Prototype = "int(...)";
573573
}
574574

@@ -646,19 +646,21 @@ def IsFPClass : Builtin {
646646
def Signbit : Builtin {
647647
let Spellings = ["__builtin_signbit"];
648648
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const,
649-
CustomTypeChecking];
649+
CustomTypeChecking, Constexpr];
650650
let Prototype = "int(...)";
651651
}
652652

653653
def SignbitF : Builtin {
654654
let Spellings = ["__builtin_signbitf"];
655-
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const];
655+
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const,
656+
Constexpr];
656657
let Prototype = "int(float)";
657658
}
658659

659660
def SignbitL : Builtin {
660661
let Spellings = ["__builtin_signbitl"];
661-
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const];
662+
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const,
663+
Constexpr];
662664
let Prototype = "int(long double)";
663665
}
664666

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,51 @@ static bool interp__builtin_iszero(InterpState &S, CodePtr OpPC,
433433
return true;
434434
}
435435

436+
static bool interp__builtin_signbit(InterpState &S, CodePtr OpPC,
437+
const InterpFrame *Frame, const Function *F,
438+
const CallExpr *Call) {
439+
const Floating &Arg = S.Stk.peek<Floating>();
440+
441+
pushInteger(S, Arg.isNegative(), Call->getType());
442+
return true;
443+
}
444+
445+
static bool interp_floating_comparison(InterpState &S, CodePtr OpPC,
446+
const InterpFrame *Frame,
447+
const Function *F,
448+
const CallExpr *Call) {
449+
const Floating &RHS = S.Stk.peek<Floating>();
450+
const Floating &LHS = S.Stk.peek<Floating>(align(2u * primSize(PT_Float)));
451+
unsigned ID = F->getBuiltinID();
452+
453+
pushInteger(
454+
S,
455+
[&] {
456+
switch (ID) {
457+
case Builtin::BI__builtin_isgreater:
458+
return LHS > RHS;
459+
case Builtin::BI__builtin_isgreaterequal:
460+
return LHS >= RHS;
461+
case Builtin::BI__builtin_isless:
462+
return LHS < RHS;
463+
case Builtin::BI__builtin_islessequal:
464+
return LHS <= RHS;
465+
case Builtin::BI__builtin_islessgreater: {
466+
ComparisonCategoryResult cmp = LHS.compare(RHS);
467+
return cmp == ComparisonCategoryResult::Less ||
468+
cmp == ComparisonCategoryResult::Greater;
469+
}
470+
case Builtin::BI__builtin_isunordered:
471+
return LHS.compare(RHS) == ComparisonCategoryResult::Unordered;
472+
default:
473+
llvm_unreachable("Unexpected builtin ID: Should be a floating point "
474+
"comparison function");
475+
}
476+
}(),
477+
Call->getType());
478+
return true;
479+
}
480+
436481
/// First parameter to __builtin_isfpclass is the floating value, the
437482
/// second one is an integral value.
438483
static bool interp__builtin_isfpclass(InterpState &S, CodePtr OpPC,
@@ -1313,6 +1358,21 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
13131358
if (!interp__builtin_iszero(S, OpPC, Frame, F, Call))
13141359
return false;
13151360
break;
1361+
case Builtin::BI__builtin_signbit:
1362+
case Builtin::BI__builtin_signbitf:
1363+
case Builtin::BI__builtin_signbitl:
1364+
if (!interp__builtin_signbit(S, OpPC, Frame, F, Call))
1365+
return false;
1366+
break;
1367+
case Builtin::BI__builtin_isgreater:
1368+
case Builtin::BI__builtin_isgreaterequal:
1369+
case Builtin::BI__builtin_isless:
1370+
case Builtin::BI__builtin_islessequal:
1371+
case Builtin::BI__builtin_islessgreater:
1372+
case Builtin::BI__builtin_isunordered:
1373+
if (!interp_floating_comparison(S, OpPC, Frame, F, Call))
1374+
return false;
1375+
break;
13161376
case Builtin::BI__builtin_isfpclass:
13171377
if (!interp__builtin_isfpclass(S, OpPC, Frame, F, Call))
13181378
return false;

clang/lib/AST/ExprConstant.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12833,6 +12833,54 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
1283312833
Success(Val.isZero() ? 1 : 0, E);
1283412834
}
1283512835

12836+
case Builtin::BI__builtin_signbit:
12837+
case Builtin::BI__builtin_signbitf:
12838+
case Builtin::BI__builtin_signbitl: {
12839+
APFloat Val(0.0);
12840+
return EvaluateFloat(E->getArg(0), Val, Info) &&
12841+
Success(Val.isNegative() ? 1 : 0, E);
12842+
}
12843+
12844+
case Builtin::BI__builtin_isgreater:
12845+
case Builtin::BI__builtin_isgreaterequal:
12846+
case Builtin::BI__builtin_isless:
12847+
case Builtin::BI__builtin_islessequal:
12848+
case Builtin::BI__builtin_islessgreater:
12849+
case Builtin::BI__builtin_isunordered: {
12850+
APFloat LHS(0.0);
12851+
APFloat RHS(0.0);
12852+
if (!EvaluateFloat(E->getArg(0), LHS, Info) ||
12853+
!EvaluateFloat(E->getArg(1), RHS, Info))
12854+
return false;
12855+
12856+
return Success(
12857+
[&] {
12858+
switch (BuiltinOp) {
12859+
case Builtin::BI__builtin_isgreater:
12860+
return LHS > RHS;
12861+
case Builtin::BI__builtin_isgreaterequal:
12862+
return LHS >= RHS;
12863+
case Builtin::BI__builtin_isless:
12864+
return LHS < RHS;
12865+
case Builtin::BI__builtin_islessequal:
12866+
return LHS <= RHS;
12867+
case Builtin::BI__builtin_islessgreater: {
12868+
APFloat::cmpResult cmp = LHS.compare(RHS);
12869+
return cmp == APFloat::cmpResult::cmpLessThan ||
12870+
cmp == APFloat::cmpResult::cmpGreaterThan;
12871+
}
12872+
case Builtin::BI__builtin_isunordered:
12873+
return LHS.compare(RHS) == APFloat::cmpResult::cmpUnordered;
12874+
default:
12875+
llvm_unreachable("Unexpected builtin ID: Should be a floating "
12876+
"point comparison function");
12877+
}
12878+
}()
12879+
? 1
12880+
: 0,
12881+
E);
12882+
}
12883+
1283612884
case Builtin::BI__builtin_issignaling: {
1283712885
APFloat Val(0.0);
1283812886
return EvaluateFloat(E->getArg(0), Val, Info) &&

clang/test/Analysis/builtin_signbit.cpp

Lines changed: 53 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -12,103 +12,83 @@ long double ld = -1.0L;
1212
// CHECK-BE32-LABEL: define dso_local void @_Z12test_signbitv(
1313
// CHECK-BE32-SAME: ) #[[ATTR0:[0-9]+]] {
1414
// CHECK-BE32-NEXT: entry:
15-
// CHECK-BE32-NEXT: [[TMP0:%.*]] = lshr i128 bitcast (ppc_fp128 0xM3FF00000000000000000000000000000 to i128), 64
16-
// CHECK-BE32-NEXT: [[TMP1:%.*]] = trunc i128 [[TMP0]] to i64
17-
// CHECK-BE32-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP1]], 0
18-
// CHECK-BE32-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP2]] to i8
15+
// CHECK-BE32-NEXT: store i8 0, ptr @b, align 1
16+
// CHECK-BE32-NEXT: [[TMP0:%.*]] = load ppc_fp128, ptr @ld, align 16
17+
// CHECK-BE32-NEXT: [[TMP1:%.*]] = bitcast ppc_fp128 [[TMP0]] to i128
18+
// CHECK-BE32-NEXT: [[TMP2:%.*]] = lshr i128 [[TMP1]], 64
19+
// CHECK-BE32-NEXT: [[TMP3:%.*]] = trunc i128 [[TMP2]] to i64
20+
// CHECK-BE32-NEXT: [[TMP4:%.*]] = icmp slt i64 [[TMP3]], 0
21+
// CHECK-BE32-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP4]] to i8
1922
// CHECK-BE32-NEXT: store i8 [[FROMBOOL]], ptr @b, align 1
20-
// CHECK-BE32-NEXT: [[TMP3:%.*]] = load ppc_fp128, ptr @ld, align 16
21-
// CHECK-BE32-NEXT: [[TMP4:%.*]] = bitcast ppc_fp128 [[TMP3]] to i128
22-
// CHECK-BE32-NEXT: [[TMP5:%.*]] = lshr i128 [[TMP4]], 64
23-
// CHECK-BE32-NEXT: [[TMP6:%.*]] = trunc i128 [[TMP5]] to i64
24-
// CHECK-BE32-NEXT: [[TMP7:%.*]] = icmp slt i64 [[TMP6]], 0
23+
// CHECK-BE32-NEXT: store i8 0, ptr @b, align 1
24+
// CHECK-BE32-NEXT: [[TMP5:%.*]] = load double, ptr @d, align 8
25+
// CHECK-BE32-NEXT: [[CONV:%.*]] = fptrunc double [[TMP5]] to float
26+
// CHECK-BE32-NEXT: [[TMP6:%.*]] = bitcast float [[CONV]] to i32
27+
// CHECK-BE32-NEXT: [[TMP7:%.*]] = icmp slt i32 [[TMP6]], 0
2528
// CHECK-BE32-NEXT: [[FROMBOOL1:%.*]] = zext i1 [[TMP7]] to i8
2629
// CHECK-BE32-NEXT: store i8 [[FROMBOOL1]], ptr @b, align 1
2730
// CHECK-BE32-NEXT: store i8 0, ptr @b, align 1
28-
// CHECK-BE32-NEXT: [[TMP8:%.*]] = load double, ptr @d, align 8
29-
// CHECK-BE32-NEXT: [[CONV:%.*]] = fptrunc double [[TMP8]] to float
30-
// CHECK-BE32-NEXT: [[TMP9:%.*]] = bitcast float [[CONV]] to i32
31-
// CHECK-BE32-NEXT: [[TMP10:%.*]] = icmp slt i32 [[TMP9]], 0
32-
// CHECK-BE32-NEXT: [[FROMBOOL2:%.*]] = zext i1 [[TMP10]] to i8
31+
// CHECK-BE32-NEXT: [[TMP8:%.*]] = load ppc_fp128, ptr @ld, align 16
32+
// CHECK-BE32-NEXT: [[TMP9:%.*]] = bitcast ppc_fp128 [[TMP8]] to i128
33+
// CHECK-BE32-NEXT: [[TMP10:%.*]] = lshr i128 [[TMP9]], 64
34+
// CHECK-BE32-NEXT: [[TMP11:%.*]] = trunc i128 [[TMP10]] to i64
35+
// CHECK-BE32-NEXT: [[TMP12:%.*]] = icmp slt i64 [[TMP11]], 0
36+
// CHECK-BE32-NEXT: [[FROMBOOL2:%.*]] = zext i1 [[TMP12]] to i8
3337
// CHECK-BE32-NEXT: store i8 [[FROMBOOL2]], ptr @b, align 1
34-
// CHECK-BE32-NEXT: [[TMP11:%.*]] = lshr i128 bitcast (ppc_fp128 0xM3FF00000000000000000000000000000 to i128), 64
35-
// CHECK-BE32-NEXT: [[TMP12:%.*]] = trunc i128 [[TMP11]] to i64
36-
// CHECK-BE32-NEXT: [[TMP13:%.*]] = icmp slt i64 [[TMP12]], 0
37-
// CHECK-BE32-NEXT: [[FROMBOOL3:%.*]] = zext i1 [[TMP13]] to i8
38-
// CHECK-BE32-NEXT: store i8 [[FROMBOOL3]], ptr @b, align 1
39-
// CHECK-BE32-NEXT: [[TMP14:%.*]] = load ppc_fp128, ptr @ld, align 16
40-
// CHECK-BE32-NEXT: [[TMP15:%.*]] = bitcast ppc_fp128 [[TMP14]] to i128
41-
// CHECK-BE32-NEXT: [[TMP16:%.*]] = lshr i128 [[TMP15]], 64
42-
// CHECK-BE32-NEXT: [[TMP17:%.*]] = trunc i128 [[TMP16]] to i64
43-
// CHECK-BE32-NEXT: [[TMP18:%.*]] = icmp slt i64 [[TMP17]], 0
44-
// CHECK-BE32-NEXT: [[FROMBOOL4:%.*]] = zext i1 [[TMP18]] to i8
45-
// CHECK-BE32-NEXT: store i8 [[FROMBOOL4]], ptr @b, align 1
4638
// CHECK-BE32-NEXT: ret void
4739
//
4840
// CHECK-BE64-LABEL: define dso_local void @_Z12test_signbitv(
4941
// CHECK-BE64-SAME: ) #[[ATTR0:[0-9]+]] {
5042
// CHECK-BE64-NEXT: entry:
51-
// CHECK-BE64-NEXT: [[TMP0:%.*]] = lshr i128 bitcast (ppc_fp128 0xM3FF00000000000000000000000000000 to i128), 64
52-
// CHECK-BE64-NEXT: [[TMP1:%.*]] = trunc i128 [[TMP0]] to i64
53-
// CHECK-BE64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP1]], 0
54-
// CHECK-BE64-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP2]] to i8
43+
// CHECK-BE64-NEXT: store i8 0, ptr @b, align 1
44+
// CHECK-BE64-NEXT: [[TMP0:%.*]] = load ppc_fp128, ptr @ld, align 16
45+
// CHECK-BE64-NEXT: [[TMP1:%.*]] = bitcast ppc_fp128 [[TMP0]] to i128
46+
// CHECK-BE64-NEXT: [[TMP2:%.*]] = lshr i128 [[TMP1]], 64
47+
// CHECK-BE64-NEXT: [[TMP3:%.*]] = trunc i128 [[TMP2]] to i64
48+
// CHECK-BE64-NEXT: [[TMP4:%.*]] = icmp slt i64 [[TMP3]], 0
49+
// CHECK-BE64-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP4]] to i8
5550
// CHECK-BE64-NEXT: store i8 [[FROMBOOL]], ptr @b, align 1
56-
// CHECK-BE64-NEXT: [[TMP3:%.*]] = load ppc_fp128, ptr @ld, align 16
57-
// CHECK-BE64-NEXT: [[TMP4:%.*]] = bitcast ppc_fp128 [[TMP3]] to i128
58-
// CHECK-BE64-NEXT: [[TMP5:%.*]] = lshr i128 [[TMP4]], 64
59-
// CHECK-BE64-NEXT: [[TMP6:%.*]] = trunc i128 [[TMP5]] to i64
60-
// CHECK-BE64-NEXT: [[TMP7:%.*]] = icmp slt i64 [[TMP6]], 0
51+
// CHECK-BE64-NEXT: store i8 0, ptr @b, align 1
52+
// CHECK-BE64-NEXT: [[TMP5:%.*]] = load double, ptr @d, align 8
53+
// CHECK-BE64-NEXT: [[CONV:%.*]] = fptrunc double [[TMP5]] to float
54+
// CHECK-BE64-NEXT: [[TMP6:%.*]] = bitcast float [[CONV]] to i32
55+
// CHECK-BE64-NEXT: [[TMP7:%.*]] = icmp slt i32 [[TMP6]], 0
6156
// CHECK-BE64-NEXT: [[FROMBOOL1:%.*]] = zext i1 [[TMP7]] to i8
6257
// CHECK-BE64-NEXT: store i8 [[FROMBOOL1]], ptr @b, align 1
6358
// CHECK-BE64-NEXT: store i8 0, ptr @b, align 1
64-
// CHECK-BE64-NEXT: [[TMP8:%.*]] = load double, ptr @d, align 8
65-
// CHECK-BE64-NEXT: [[CONV:%.*]] = fptrunc double [[TMP8]] to float
66-
// CHECK-BE64-NEXT: [[TMP9:%.*]] = bitcast float [[CONV]] to i32
67-
// CHECK-BE64-NEXT: [[TMP10:%.*]] = icmp slt i32 [[TMP9]], 0
68-
// CHECK-BE64-NEXT: [[FROMBOOL2:%.*]] = zext i1 [[TMP10]] to i8
59+
// CHECK-BE64-NEXT: [[TMP8:%.*]] = load ppc_fp128, ptr @ld, align 16
60+
// CHECK-BE64-NEXT: [[TMP9:%.*]] = bitcast ppc_fp128 [[TMP8]] to i128
61+
// CHECK-BE64-NEXT: [[TMP10:%.*]] = lshr i128 [[TMP9]], 64
62+
// CHECK-BE64-NEXT: [[TMP11:%.*]] = trunc i128 [[TMP10]] to i64
63+
// CHECK-BE64-NEXT: [[TMP12:%.*]] = icmp slt i64 [[TMP11]], 0
64+
// CHECK-BE64-NEXT: [[FROMBOOL2:%.*]] = zext i1 [[TMP12]] to i8
6965
// CHECK-BE64-NEXT: store i8 [[FROMBOOL2]], ptr @b, align 1
70-
// CHECK-BE64-NEXT: [[TMP11:%.*]] = lshr i128 bitcast (ppc_fp128 0xM3FF00000000000000000000000000000 to i128), 64
71-
// CHECK-BE64-NEXT: [[TMP12:%.*]] = trunc i128 [[TMP11]] to i64
72-
// CHECK-BE64-NEXT: [[TMP13:%.*]] = icmp slt i64 [[TMP12]], 0
73-
// CHECK-BE64-NEXT: [[FROMBOOL3:%.*]] = zext i1 [[TMP13]] to i8
74-
// CHECK-BE64-NEXT: store i8 [[FROMBOOL3]], ptr @b, align 1
75-
// CHECK-BE64-NEXT: [[TMP14:%.*]] = load ppc_fp128, ptr @ld, align 16
76-
// CHECK-BE64-NEXT: [[TMP15:%.*]] = bitcast ppc_fp128 [[TMP14]] to i128
77-
// CHECK-BE64-NEXT: [[TMP16:%.*]] = lshr i128 [[TMP15]], 64
78-
// CHECK-BE64-NEXT: [[TMP17:%.*]] = trunc i128 [[TMP16]] to i64
79-
// CHECK-BE64-NEXT: [[TMP18:%.*]] = icmp slt i64 [[TMP17]], 0
80-
// CHECK-BE64-NEXT: [[FROMBOOL4:%.*]] = zext i1 [[TMP18]] to i8
81-
// CHECK-BE64-NEXT: store i8 [[FROMBOOL4]], ptr @b, align 1
8266
// CHECK-BE64-NEXT: ret void
8367
//
8468
// CHECK-LE-LABEL: define dso_local void @_Z12test_signbitv(
8569
// CHECK-LE-SAME: ) #[[ATTR0:[0-9]+]] {
8670
// CHECK-LE-NEXT: entry:
87-
// CHECK-LE-NEXT: [[TMP0:%.*]] = icmp slt i64 trunc (i128 bitcast (ppc_fp128 0xM3FF00000000000000000000000000000 to i128) to i64), 0
88-
// CHECK-LE-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP0]] to i8
71+
// CHECK-LE-NEXT: store i8 0, ptr @b, align 1
72+
// CHECK-LE-NEXT: [[TMP0:%.*]] = load ppc_fp128, ptr @ld, align 16
73+
// CHECK-LE-NEXT: [[TMP1:%.*]] = bitcast ppc_fp128 [[TMP0]] to i128
74+
// CHECK-LE-NEXT: [[TMP2:%.*]] = trunc i128 [[TMP1]] to i64
75+
// CHECK-LE-NEXT: [[TMP3:%.*]] = icmp slt i64 [[TMP2]], 0
76+
// CHECK-LE-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP3]] to i8
8977
// CHECK-LE-NEXT: store i8 [[FROMBOOL]], ptr @b, align 1
90-
// CHECK-LE-NEXT: [[TMP1:%.*]] = load ppc_fp128, ptr @ld, align 16
91-
// CHECK-LE-NEXT: [[TMP2:%.*]] = bitcast ppc_fp128 [[TMP1]] to i128
92-
// CHECK-LE-NEXT: [[TMP3:%.*]] = trunc i128 [[TMP2]] to i64
93-
// CHECK-LE-NEXT: [[TMP4:%.*]] = icmp slt i64 [[TMP3]], 0
94-
// CHECK-LE-NEXT: [[FROMBOOL1:%.*]] = zext i1 [[TMP4]] to i8
78+
// CHECK-LE-NEXT: store i8 0, ptr @b, align 1
79+
// CHECK-LE-NEXT: [[TMP4:%.*]] = load double, ptr @d, align 8
80+
// CHECK-LE-NEXT: [[CONV:%.*]] = fptrunc double [[TMP4]] to float
81+
// CHECK-LE-NEXT: [[TMP5:%.*]] = bitcast float [[CONV]] to i32
82+
// CHECK-LE-NEXT: [[TMP6:%.*]] = icmp slt i32 [[TMP5]], 0
83+
// CHECK-LE-NEXT: [[FROMBOOL1:%.*]] = zext i1 [[TMP6]] to i8
9584
// CHECK-LE-NEXT: store i8 [[FROMBOOL1]], ptr @b, align 1
9685
// CHECK-LE-NEXT: store i8 0, ptr @b, align 1
97-
// CHECK-LE-NEXT: [[TMP5:%.*]] = load double, ptr @d, align 8
98-
// CHECK-LE-NEXT: [[CONV:%.*]] = fptrunc double [[TMP5]] to float
99-
// CHECK-LE-NEXT: [[TMP6:%.*]] = bitcast float [[CONV]] to i32
100-
// CHECK-LE-NEXT: [[TMP7:%.*]] = icmp slt i32 [[TMP6]], 0
101-
// CHECK-LE-NEXT: [[FROMBOOL2:%.*]] = zext i1 [[TMP7]] to i8
86+
// CHECK-LE-NEXT: [[TMP7:%.*]] = load ppc_fp128, ptr @ld, align 16
87+
// CHECK-LE-NEXT: [[TMP8:%.*]] = bitcast ppc_fp128 [[TMP7]] to i128
88+
// CHECK-LE-NEXT: [[TMP9:%.*]] = trunc i128 [[TMP8]] to i64
89+
// CHECK-LE-NEXT: [[TMP10:%.*]] = icmp slt i64 [[TMP9]], 0
90+
// CHECK-LE-NEXT: [[FROMBOOL2:%.*]] = zext i1 [[TMP10]] to i8
10291
// CHECK-LE-NEXT: store i8 [[FROMBOOL2]], ptr @b, align 1
103-
// CHECK-LE-NEXT: [[TMP8:%.*]] = icmp slt i64 trunc (i128 bitcast (ppc_fp128 0xM3FF00000000000000000000000000000 to i128) to i64), 0
104-
// CHECK-LE-NEXT: [[FROMBOOL3:%.*]] = zext i1 [[TMP8]] to i8
105-
// CHECK-LE-NEXT: store i8 [[FROMBOOL3]], ptr @b, align 1
106-
// CHECK-LE-NEXT: [[TMP9:%.*]] = load ppc_fp128, ptr @ld, align 16
107-
// CHECK-LE-NEXT: [[TMP10:%.*]] = bitcast ppc_fp128 [[TMP9]] to i128
108-
// CHECK-LE-NEXT: [[TMP11:%.*]] = trunc i128 [[TMP10]] to i64
109-
// CHECK-LE-NEXT: [[TMP12:%.*]] = icmp slt i64 [[TMP11]], 0
110-
// CHECK-LE-NEXT: [[FROMBOOL4:%.*]] = zext i1 [[TMP12]] to i8
111-
// CHECK-LE-NEXT: store i8 [[FROMBOOL4]], ptr @b, align 1
11292
// CHECK-LE-NEXT: ret void
11393
//
11494
void test_signbit()

0 commit comments

Comments
 (0)