r232778 - [Modules] Implement __builtin_isinf_sign in Clang.
Chandler Carruth
chandlerc at gmail.com
Thu Mar 19 15:39:51 PDT 2015
Author: chandlerc
Date: Thu Mar 19 17:39:51 2015
New Revision: 232778
URL: http://llvm.org/viewvc/llvm-project?rev=232778&view=rev
Log:
[Modules] Implement __builtin_isinf_sign in Clang.
Somehow, we never managed to implement this fully. We could constant
fold it like crazy, including constant folding complex arguments, etc.
But if you actually needed to generate code for it, error.
I've implemented it using the somewhat obvious lowering. Happy for
suggestions on a more clever way to lower this.
Now, what you might ask does this have to do with modules? Fun story. So
it turns out that libstdc++ actually uses __builtin_isinf_sign to
implement std::isinf when in C++98 mode, but only inside of a template.
So if we're lucky, and we never instantiate that, everything is good.
But once we try to instantiate that template function, we need this
builtin. All of my customers at least are using C++11 and so they never
hit this code path.
But what does that have to do with modules? Fun story. So it turns out
that with modules we actually observe a bunch of bugs in libstdc++ where
their <cmath> header clobbers things exposed by <math.h>. To fix these,
we have to provide global function definitions to replace the macros
that C99 would have used. And it turns out that ::isinf needs to be
implemented using the exact semantics used by the C++98 variant of
std::isinf. And so I started to fix this bug in libstdc++ and ceased to
be able to compile libstdc++ with Clang.
The yaks are legion.
Modified:
cfe/trunk/lib/CodeGen/CGBuiltin.cpp
cfe/trunk/test/CodeGen/builtins.c
Modified: cfe/trunk/lib/CodeGen/CGBuiltin.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBuiltin.cpp?rev=232778&r1=232777&r2=232778&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGBuiltin.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGBuiltin.cpp Thu Mar 19 17:39:51 2015
@@ -158,6 +158,27 @@ static Value *EmitFAbs(CodeGenFunction &
return Call;
}
+/// Emit the computation of the sign bit for a floating point value. Returns
+/// the i1 sign bit value.
+static Value *EmitSignBit(CodeGenFunction &CGF, Value *V) {
+ LLVMContext &C = CGF.CGM.getLLVMContext();
+
+ llvm::Type *Ty = V->getType();
+ int Width = Ty->getPrimitiveSizeInBits();
+ llvm::Type *IntTy = llvm::IntegerType::get(C, Width);
+ V = CGF.Builder.CreateBitCast(V, IntTy);
+ if (Ty->isPPC_FP128Ty()) {
+ // The higher-order double comes first, and so we need to truncate the
+ // pair to extract the overall sign. The order of the pair is the same
+ // in both little- and big-Endian modes.
+ Width >>= 1;
+ IntTy = llvm::IntegerType::get(C, Width);
+ V = CGF.Builder.CreateTrunc(V, IntTy);
+ }
+ Value *Zero = llvm::Constant::getNullValue(IntTy);
+ return CGF.Builder.CreateICmpSLT(V, Zero);
+}
+
static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *Fn,
const CallExpr *E, llvm::Value *calleeValue) {
return CGF.EmitCall(E->getCallee()->getType(), calleeValue, E,
@@ -558,8 +579,22 @@ RValue CodeGenFunction::EmitBuiltinExpr(
return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType())));
}
- // TODO: BI__builtin_isinf_sign
- // isinf_sign(x) -> isinf(x) ? (signbit(x) ? -1 : 1) : 0
+ case Builtin::BI__builtin_isinf_sign: {
+ // isinf_sign(x) -> fabs(x) == infinity ? (signbit(x) ? -1 : 1) : 0
+ Value *Arg = EmitScalarExpr(E->getArg(0));
+ Value *AbsArg = EmitFAbs(*this, Arg);
+ Value *IsInf = Builder.CreateFCmpOEQ(
+ AbsArg, ConstantFP::getInfinity(Arg->getType()), "isinf");
+ Value *IsNeg = EmitSignBit(*this, Arg);
+
+ llvm::Type *IntTy = ConvertType(E->getType());
+ Value *Zero = Constant::getNullValue(IntTy);
+ Value *One = ConstantInt::get(IntTy, 1);
+ Value *NegativeOne = ConstantInt::get(IntTy, -1);
+ Value *SignResult = Builder.CreateSelect(IsNeg, NegativeOne, One);
+ Value *Result = Builder.CreateSelect(IsInf, SignResult, Zero);
+ return RValue::get(Result);
+ }
case Builtin::BI__builtin_isnormal: {
// isnormal(x) --> x == x && fabsf(x) < infinity && fabsf(x) >= float_min
@@ -1398,24 +1433,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(
case Builtin::BI__builtin_signbit:
case Builtin::BI__builtin_signbitf:
case Builtin::BI__builtin_signbitl: {
- LLVMContext &C = CGM.getLLVMContext();
-
- Value *Arg = EmitScalarExpr(E->getArg(0));
- llvm::Type *ArgTy = Arg->getType();
- int ArgWidth = ArgTy->getPrimitiveSizeInBits();
- llvm::Type *ArgIntTy = llvm::IntegerType::get(C, ArgWidth);
- Value *BCArg = Builder.CreateBitCast(Arg, ArgIntTy);
- if (ArgTy->isPPC_FP128Ty()) {
- // The higher-order double comes first, and so we need to truncate the
- // pair to extract the overall sign. The order of the pair is the same
- // in both little- and big-Endian modes.
- ArgWidth >>= 1;
- ArgIntTy = llvm::IntegerType::get(C, ArgWidth);
- BCArg = Builder.CreateTrunc(BCArg, ArgIntTy);
- }
- Value *ZeroCmp = llvm::Constant::getNullValue(ArgIntTy);
- Value *Result = Builder.CreateICmpSLT(BCArg, ZeroCmp);
- return RValue::get(Builder.CreateZExt(Result, ConvertType(E->getType())));
+ return RValue::get(
+ Builder.CreateZExt(EmitSignBit(*this, EmitScalarExpr(E->getArg(0))),
+ ConvertType(E->getType())));
}
case Builtin::BI__builtin_annotation: {
llvm::Value *AnnVal = EmitScalarExpr(E->getArg(0));
Modified: cfe/trunk/test/CodeGen/builtins.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/builtins.c?rev=232778&r1=232777&r2=232778&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/builtins.c (original)
+++ cfe/trunk/test/CodeGen/builtins.c Thu Mar 19 17:39:51 2015
@@ -42,8 +42,6 @@ int main() {
P(fpclassify, (0, 1, 2, 3, 4, 1.0));
P(fpclassify, (0, 1, 2, 3, 4, 1.0f));
P(fpclassify, (0, 1, 2, 3, 4, 1.0l));
- // FIXME:
- // P(isinf_sign, (1.0));
Q(nan, (""));
Q(nanf, (""));
@@ -61,6 +59,8 @@ int main() {
P(islessgreater, (1., 2.));
P(isunordered, (1., 2.));
+ P(isinf, (1.));
+ P(isinf_sign, (1.));
P(isnan, (1.));
// Bitwise & Numeric Functions
@@ -177,11 +177,35 @@ void test_float_builtins(float F, double
res = __builtin_isinf(D);
// CHECK: call double @llvm.fabs.f64(double
// CHECK: fcmp oeq double {{.*}}, 0x7FF0000000000000
-
+
res = __builtin_isinf(LD);
// CHECK: call x86_fp80 @llvm.fabs.f80(x86_fp80
// CHECK: fcmp oeq x86_fp80 {{.*}}, 0xK7FFF8000000000000000
-
+
+ res = __builtin_isinf_sign(F);
+ // CHECK: %[[ABS:.*]] = call float @llvm.fabs.f32(float %[[ARG:.*]])
+ // CHECK: %[[ISINF:.*]] = fcmp oeq float %[[ABS]], 0x7FF0000000000000
+ // CHECK: %[[BITCAST:.*]] = bitcast float %[[ARG]] to i32
+ // CHECK: %[[ISNEG:.*]] = icmp slt i32 %[[BITCAST]], 0
+ // CHECK: %[[SIGN:.*]] = select i1 %[[ISNEG]], i32 -1, i32 1
+ // CHECK: select i1 %[[ISINF]], i32 %[[SIGN]], i32 0
+
+ res = __builtin_isinf_sign(D);
+ // CHECK: %[[ABS:.*]] = call double @llvm.fabs.f64(double %[[ARG:.*]])
+ // CHECK: %[[ISINF:.*]] = fcmp oeq double %[[ABS]], 0x7FF0000000000000
+ // CHECK: %[[BITCAST:.*]] = bitcast double %[[ARG]] to i64
+ // CHECK: %[[ISNEG:.*]] = icmp slt i64 %[[BITCAST]], 0
+ // CHECK: %[[SIGN:.*]] = select i1 %[[ISNEG]], i32 -1, i32 1
+ // CHECK: select i1 %[[ISINF]], i32 %[[SIGN]], i32 0
+
+ res = __builtin_isinf_sign(LD);
+ // CHECK: %[[ABS:.*]] = call x86_fp80 @llvm.fabs.f80(x86_fp80 %[[ARG:.*]])
+ // CHECK: %[[ISINF:.*]] = fcmp oeq x86_fp80 %[[ABS]], 0xK7FFF8000000000000000
+ // CHECK: %[[BITCAST:.*]] = bitcast x86_fp80 %[[ARG]] to i80
+ // CHECK: %[[ISNEG:.*]] = icmp slt i80 %[[BITCAST]], 0
+ // CHECK: %[[SIGN:.*]] = select i1 %[[ISNEG]], i32 -1, i32 1
+ // CHECK: select i1 %[[ISINF]], i32 %[[SIGN]], i32 0
+
res = __builtin_isfinite(F);
// CHECK: fcmp oeq float
// CHECK: call float @llvm.fabs.f32(float
More information about the cfe-commits
mailing list