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