2007-08-21 02:05:56 +08:00
|
|
|
//===---- CGBuiltin.cpp - Emit LLVM Code for builtins ---------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-30 03:59:25 +08:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2007-08-21 02:05:56 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This contains code to emit Builtin calls as LLVM code.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-03-02 11:50:12 +08:00
|
|
|
#include "TargetInfo.h"
|
2007-08-21 02:05:56 +08:00
|
|
|
#include "CodeGenFunction.h"
|
|
|
|
#include "CodeGenModule.h"
|
2007-12-10 05:20:04 +08:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
2008-10-06 14:09:18 +08:00
|
|
|
#include "clang/AST/APValue.h"
|
2007-08-31 12:31:45 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2008-08-11 13:35:13 +08:00
|
|
|
#include "clang/AST/Decl.h"
|
2009-06-14 09:05:48 +08:00
|
|
|
#include "clang/Basic/TargetBuiltins.h"
|
2007-10-13 07:56:29 +08:00
|
|
|
#include "llvm/Intrinsics.h"
|
2010-03-02 11:50:12 +08:00
|
|
|
#include "llvm/Target/TargetData.h"
|
2007-08-21 02:05:56 +08:00
|
|
|
using namespace clang;
|
|
|
|
using namespace CodeGen;
|
2007-12-10 05:20:04 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
2010-03-20 15:04:11 +08:00
|
|
|
static void EmitMemoryBarrier(CodeGenFunction &CGF,
|
|
|
|
bool LoadLoad, bool LoadStore,
|
|
|
|
bool StoreLoad, bool StoreStore,
|
|
|
|
bool Device) {
|
|
|
|
Value *True = llvm::ConstantInt::getTrue(CGF.getLLVMContext());
|
|
|
|
Value *False = llvm::ConstantInt::getFalse(CGF.getLLVMContext());
|
|
|
|
Value *C[5] = { LoadLoad ? True : False,
|
|
|
|
LoadStore ? True : False,
|
|
|
|
StoreLoad ? True : False,
|
|
|
|
StoreStore ? True : False,
|
|
|
|
Device ? True : False };
|
|
|
|
CGF.Builder.CreateCall(CGF.CGM.getIntrinsic(Intrinsic::memory_barrier),
|
|
|
|
C, C + 5);
|
|
|
|
}
|
|
|
|
|
|
|
|
// The atomic builtins are also full memory barriers. This is a utility for
|
|
|
|
// wrapping a call to the builtins with memory barriers.
|
|
|
|
static Value *EmitCallWithBarrier(CodeGenFunction &CGF, Value *Fn,
|
|
|
|
Value **ArgBegin, Value **ArgEnd) {
|
|
|
|
// FIXME: We need a target hook for whether this applies to device memory or
|
|
|
|
// not.
|
|
|
|
bool Device = true;
|
|
|
|
|
|
|
|
// Create barriers both before and after the call.
|
|
|
|
EmitMemoryBarrier(CGF, true, true, true, true, Device);
|
|
|
|
Value *Result = CGF.Builder.CreateCall(Fn, ArgBegin, ArgEnd);
|
|
|
|
EmitMemoryBarrier(CGF, true, true, true, true, Device);
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2009-04-07 08:55:51 +08:00
|
|
|
/// Utility to insert an atomic instruction based on Instrinsic::ID
|
|
|
|
/// and the expression node.
|
2010-03-20 15:04:11 +08:00
|
|
|
static RValue EmitBinaryAtomic(CodeGenFunction &CGF,
|
2008-05-10 06:40:52 +08:00
|
|
|
Intrinsic::ID Id, const CallExpr *E) {
|
2010-03-20 15:04:11 +08:00
|
|
|
Value *Args[2] = { CGF.EmitScalarExpr(E->getArg(0)),
|
|
|
|
CGF.EmitScalarExpr(E->getArg(1)) };
|
2008-07-31 11:28:23 +08:00
|
|
|
const llvm::Type *ResType[2];
|
2009-04-07 08:55:51 +08:00
|
|
|
ResType[0] = CGF.ConvertType(E->getType());
|
|
|
|
ResType[1] = CGF.ConvertType(E->getArg(0)->getType());
|
|
|
|
Value *AtomF = CGF.CGM.getIntrinsic(Id, ResType, 2);
|
2010-03-20 15:04:11 +08:00
|
|
|
return RValue::get(EmitCallWithBarrier(CGF, AtomF, Args, Args + 2));
|
2009-04-07 08:55:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Utility to insert an atomic instruction based Instrinsic::ID and
|
|
|
|
// the expression node, where the return value is the result of the
|
|
|
|
// operation.
|
2010-05-06 13:35:16 +08:00
|
|
|
static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF,
|
2009-04-07 08:55:51 +08:00
|
|
|
Intrinsic::ID Id, const CallExpr *E,
|
|
|
|
Instruction::BinaryOps Op) {
|
|
|
|
const llvm::Type *ResType[2];
|
|
|
|
ResType[0] = CGF.ConvertType(E->getType());
|
|
|
|
ResType[1] = CGF.ConvertType(E->getArg(0)->getType());
|
|
|
|
Value *AtomF = CGF.CGM.getIntrinsic(Id, ResType, 2);
|
2010-03-20 15:04:11 +08:00
|
|
|
Value *Args[2] = { CGF.EmitScalarExpr(E->getArg(0)),
|
|
|
|
CGF.EmitScalarExpr(E->getArg(1)) };
|
|
|
|
Value *Result = EmitCallWithBarrier(CGF, AtomF, Args, Args + 2);
|
|
|
|
return RValue::get(CGF.Builder.CreateBinOp(Op, Result, Args[1]));
|
2008-05-10 06:40:52 +08:00
|
|
|
}
|
|
|
|
|
2010-03-03 18:30:05 +08:00
|
|
|
static llvm::ConstantInt *getInt32(llvm::LLVMContext &Context, int32_t Value) {
|
|
|
|
return llvm::ConstantInt::get(llvm::Type::getInt32Ty(Context), Value);
|
|
|
|
}
|
|
|
|
|
2010-05-06 13:35:16 +08:00
|
|
|
|
|
|
|
/// EmitFAbs - Emit a call to fabs/fabsf/fabsl, depending on the type of ValTy,
|
|
|
|
/// which must be a scalar floating point type.
|
|
|
|
static Value *EmitFAbs(CodeGenFunction &CGF, Value *V, QualType ValTy) {
|
|
|
|
const BuiltinType *ValTyP = ValTy->getAs<BuiltinType>();
|
|
|
|
assert(ValTyP && "isn't scalar fp type!");
|
|
|
|
|
|
|
|
StringRef FnName;
|
|
|
|
switch (ValTyP->getKind()) {
|
|
|
|
default: assert(0 && "Isn't a scalar fp type!");
|
|
|
|
case BuiltinType::Float: FnName = "fabsf"; break;
|
|
|
|
case BuiltinType::Double: FnName = "fabs"; break;
|
|
|
|
case BuiltinType::LongDouble: FnName = "fabsl"; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The prototype is something that takes and returns whatever V's type is.
|
|
|
|
std::vector<const llvm::Type*> Args;
|
|
|
|
Args.push_back(V->getType());
|
|
|
|
llvm::FunctionType *FT = llvm::FunctionType::get(V->getType(), Args, false);
|
|
|
|
llvm::Value *Fn = CGF.CGM.CreateRuntimeFunction(FT, FnName);
|
|
|
|
|
|
|
|
return CGF.Builder.CreateCall(Fn, V, "abs");
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
|
2009-02-17 06:43:43 +08:00
|
|
|
unsigned BuiltinID, const CallExpr *E) {
|
2008-10-06 14:56:41 +08:00
|
|
|
// See if we can constant fold this builtin. If so, don't emit it at all.
|
2008-12-01 10:31:41 +08:00
|
|
|
Expr::EvalResult Result;
|
2008-11-17 05:24:15 +08:00
|
|
|
if (E->Evaluate(Result, CGM.getContext())) {
|
2008-12-01 10:31:41 +08:00
|
|
|
if (Result.Val.isInt())
|
2009-09-09 23:08:12 +08:00
|
|
|
return RValue::get(llvm::ConstantInt::get(VMContext,
|
2009-07-25 07:12:58 +08:00
|
|
|
Result.Val.getInt()));
|
2009-01-25 09:54:01 +08:00
|
|
|
else if (Result.Val.isFloat())
|
2009-07-28 05:00:51 +08:00
|
|
|
return RValue::get(ConstantFP::get(VMContext, Result.Val.getFloat()));
|
2008-10-06 14:09:18 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-06 14:56:41 +08:00
|
|
|
switch (BuiltinID) {
|
|
|
|
default: break; // Handle intrinsics and libm functions below.
|
2008-10-06 15:26:43 +08:00
|
|
|
case Builtin::BI__builtin___CFStringMakeConstantString:
|
2010-01-23 10:40:42 +08:00
|
|
|
case Builtin::BI__builtin___NSStringMakeConstantString:
|
2009-04-08 12:48:15 +08:00
|
|
|
return RValue::get(CGM.EmitConstantExpr(E, E->getType(), 0));
|
2008-07-10 01:28:44 +08:00
|
|
|
case Builtin::BI__builtin_stdarg_start:
|
2007-10-13 07:56:29 +08:00
|
|
|
case Builtin::BI__builtin_va_start:
|
|
|
|
case Builtin::BI__builtin_va_end: {
|
2009-02-12 06:25:55 +08:00
|
|
|
Value *ArgValue = EmitVAListRef(E->getArg(0));
|
2009-10-13 18:07:13 +08:00
|
|
|
const llvm::Type *DestType = llvm::Type::getInt8PtrTy(VMContext);
|
2007-10-13 07:56:29 +08:00
|
|
|
if (ArgValue->getType() != DestType)
|
2009-09-09 23:08:12 +08:00
|
|
|
ArgValue = Builder.CreateBitCast(ArgValue, DestType,
|
2009-07-26 17:28:40 +08:00
|
|
|
ArgValue->getName().data());
|
2007-10-13 07:56:29 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
Intrinsic::ID inst = (BuiltinID == Builtin::BI__builtin_va_end) ?
|
2008-07-10 01:28:44 +08:00
|
|
|
Intrinsic::vaend : Intrinsic::vastart;
|
2007-12-18 08:25:38 +08:00
|
|
|
return RValue::get(Builder.CreateCall(CGM.getIntrinsic(inst), ArgValue));
|
2007-10-13 07:56:29 +08:00
|
|
|
}
|
2008-02-10 04:26:43 +08:00
|
|
|
case Builtin::BI__builtin_va_copy: {
|
2009-01-21 01:46:04 +08:00
|
|
|
Value *DstPtr = EmitVAListRef(E->getArg(0));
|
|
|
|
Value *SrcPtr = EmitVAListRef(E->getArg(1));
|
2008-02-10 04:26:43 +08:00
|
|
|
|
2009-10-13 18:07:13 +08:00
|
|
|
const llvm::Type *Type = llvm::Type::getInt8PtrTy(VMContext);
|
2008-02-10 04:26:43 +08:00
|
|
|
|
|
|
|
DstPtr = Builder.CreateBitCast(DstPtr, Type);
|
|
|
|
SrcPtr = Builder.CreateBitCast(SrcPtr, Type);
|
2009-09-09 23:08:12 +08:00
|
|
|
return RValue::get(Builder.CreateCall2(CGM.getIntrinsic(Intrinsic::vacopy),
|
2008-05-06 08:56:42 +08:00
|
|
|
DstPtr, SrcPtr));
|
2008-02-10 04:26:43 +08:00
|
|
|
}
|
2007-11-21 03:05:17 +08:00
|
|
|
case Builtin::BI__builtin_abs: {
|
2009-09-09 23:08:12 +08:00
|
|
|
Value *ArgValue = EmitScalarExpr(E->getArg(0));
|
|
|
|
|
2008-07-23 14:53:34 +08:00
|
|
|
Value *NegOp = Builder.CreateNeg(ArgValue, "neg");
|
2009-09-09 23:08:12 +08:00
|
|
|
Value *CmpResult =
|
|
|
|
Builder.CreateICmpSGE(ArgValue,
|
2009-08-01 04:28:54 +08:00
|
|
|
llvm::Constant::getNullValue(ArgValue->getType()),
|
2008-07-23 14:53:34 +08:00
|
|
|
"abscond");
|
2009-09-09 23:08:12 +08:00
|
|
|
Value *Result =
|
2007-11-21 03:05:17 +08:00
|
|
|
Builder.CreateSelect(CmpResult, ArgValue, NegOp, "abs");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-11-21 03:05:17 +08:00
|
|
|
return RValue::get(Result);
|
|
|
|
}
|
2008-02-06 15:19:27 +08:00
|
|
|
case Builtin::BI__builtin_ctz:
|
|
|
|
case Builtin::BI__builtin_ctzl:
|
|
|
|
case Builtin::BI__builtin_ctzll: {
|
|
|
|
Value *ArgValue = EmitScalarExpr(E->getArg(0));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-06 15:19:27 +08:00
|
|
|
const llvm::Type *ArgType = ArgValue->getType();
|
|
|
|
Value *F = CGM.getIntrinsic(Intrinsic::cttz, &ArgType, 1);
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
const llvm::Type *ResultType = ConvertType(E->getType());
|
2008-02-06 15:19:27 +08:00
|
|
|
Value *Result = Builder.CreateCall(F, ArgValue, "tmp");
|
|
|
|
if (Result->getType() != ResultType)
|
2009-11-16 21:11:21 +08:00
|
|
|
Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
|
|
|
|
"cast");
|
2008-02-06 15:19:27 +08:00
|
|
|
return RValue::get(Result);
|
|
|
|
}
|
2008-05-27 23:32:46 +08:00
|
|
|
case Builtin::BI__builtin_clz:
|
|
|
|
case Builtin::BI__builtin_clzl:
|
|
|
|
case Builtin::BI__builtin_clzll: {
|
|
|
|
Value *ArgValue = EmitScalarExpr(E->getArg(0));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-05-27 23:32:46 +08:00
|
|
|
const llvm::Type *ArgType = ArgValue->getType();
|
|
|
|
Value *F = CGM.getIntrinsic(Intrinsic::ctlz, &ArgType, 1);
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
const llvm::Type *ResultType = ConvertType(E->getType());
|
2008-05-27 23:32:46 +08:00
|
|
|
Value *Result = Builder.CreateCall(F, ArgValue, "tmp");
|
|
|
|
if (Result->getType() != ResultType)
|
2009-11-16 21:11:21 +08:00
|
|
|
Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
|
|
|
|
"cast");
|
2008-05-27 23:32:46 +08:00
|
|
|
return RValue::get(Result);
|
|
|
|
}
|
2008-07-22 01:19:41 +08:00
|
|
|
case Builtin::BI__builtin_ffs:
|
|
|
|
case Builtin::BI__builtin_ffsl:
|
|
|
|
case Builtin::BI__builtin_ffsll: {
|
|
|
|
// ffs(x) -> x ? cttz(x) + 1 : 0
|
|
|
|
Value *ArgValue = EmitScalarExpr(E->getArg(0));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-22 01:19:41 +08:00
|
|
|
const llvm::Type *ArgType = ArgValue->getType();
|
|
|
|
Value *F = CGM.getIntrinsic(Intrinsic::cttz, &ArgType, 1);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-22 01:19:41 +08:00
|
|
|
const llvm::Type *ResultType = ConvertType(E->getType());
|
2009-09-09 23:08:12 +08:00
|
|
|
Value *Tmp = Builder.CreateAdd(Builder.CreateCall(F, ArgValue, "tmp"),
|
2009-07-25 07:12:58 +08:00
|
|
|
llvm::ConstantInt::get(ArgType, 1), "tmp");
|
2009-08-01 04:28:54 +08:00
|
|
|
Value *Zero = llvm::Constant::getNullValue(ArgType);
|
2008-07-22 01:19:41 +08:00
|
|
|
Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero, "iszero");
|
|
|
|
Value *Result = Builder.CreateSelect(IsZero, Zero, Tmp, "ffs");
|
|
|
|
if (Result->getType() != ResultType)
|
2009-11-16 21:11:21 +08:00
|
|
|
Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
|
|
|
|
"cast");
|
2008-07-22 01:19:41 +08:00
|
|
|
return RValue::get(Result);
|
|
|
|
}
|
|
|
|
case Builtin::BI__builtin_parity:
|
|
|
|
case Builtin::BI__builtin_parityl:
|
|
|
|
case Builtin::BI__builtin_parityll: {
|
|
|
|
// parity(x) -> ctpop(x) & 1
|
|
|
|
Value *ArgValue = EmitScalarExpr(E->getArg(0));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-22 01:19:41 +08:00
|
|
|
const llvm::Type *ArgType = ArgValue->getType();
|
|
|
|
Value *F = CGM.getIntrinsic(Intrinsic::ctpop, &ArgType, 1);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-22 01:19:41 +08:00
|
|
|
const llvm::Type *ResultType = ConvertType(E->getType());
|
|
|
|
Value *Tmp = Builder.CreateCall(F, ArgValue, "tmp");
|
2009-09-09 23:08:12 +08:00
|
|
|
Value *Result = Builder.CreateAnd(Tmp, llvm::ConstantInt::get(ArgType, 1),
|
2008-07-22 01:19:41 +08:00
|
|
|
"tmp");
|
|
|
|
if (Result->getType() != ResultType)
|
2009-11-16 21:11:21 +08:00
|
|
|
Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
|
|
|
|
"cast");
|
2008-07-22 01:19:41 +08:00
|
|
|
return RValue::get(Result);
|
|
|
|
}
|
|
|
|
case Builtin::BI__builtin_popcount:
|
|
|
|
case Builtin::BI__builtin_popcountl:
|
|
|
|
case Builtin::BI__builtin_popcountll: {
|
|
|
|
Value *ArgValue = EmitScalarExpr(E->getArg(0));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-22 01:19:41 +08:00
|
|
|
const llvm::Type *ArgType = ArgValue->getType();
|
|
|
|
Value *F = CGM.getIntrinsic(Intrinsic::ctpop, &ArgType, 1);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-22 01:19:41 +08:00
|
|
|
const llvm::Type *ResultType = ConvertType(E->getType());
|
|
|
|
Value *Result = Builder.CreateCall(F, ArgValue, "tmp");
|
|
|
|
if (Result->getType() != ResultType)
|
2009-11-16 21:11:21 +08:00
|
|
|
Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
|
|
|
|
"cast");
|
2008-07-22 01:19:41 +08:00
|
|
|
return RValue::get(Result);
|
|
|
|
}
|
2007-12-13 15:34:23 +08:00
|
|
|
case Builtin::BI__builtin_expect:
|
2008-07-22 02:44:41 +08:00
|
|
|
// FIXME: pass expect through to LLVM
|
2007-12-13 15:34:23 +08:00
|
|
|
return RValue::get(EmitScalarExpr(E->getArg(0)));
|
2007-12-03 05:58:10 +08:00
|
|
|
case Builtin::BI__builtin_bswap32:
|
|
|
|
case Builtin::BI__builtin_bswap64: {
|
2007-12-13 15:34:23 +08:00
|
|
|
Value *ArgValue = EmitScalarExpr(E->getArg(0));
|
2007-12-03 05:58:10 +08:00
|
|
|
const llvm::Type *ArgType = ArgValue->getType();
|
2007-12-18 08:25:38 +08:00
|
|
|
Value *F = CGM.getIntrinsic(Intrinsic::bswap, &ArgType, 1);
|
2007-12-13 15:34:23 +08:00
|
|
|
return RValue::get(Builder.CreateCall(F, ArgValue, "tmp"));
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2008-09-04 05:13:56 +08:00
|
|
|
case Builtin::BI__builtin_object_size: {
|
2009-10-27 07:39:48 +08:00
|
|
|
// We pass this builtin onto the optimizer so that it can
|
|
|
|
// figure out the object size in more complex cases.
|
2009-10-28 06:09:17 +08:00
|
|
|
const llvm::Type *ResType[] = {
|
|
|
|
ConvertType(E->getType())
|
|
|
|
};
|
2009-12-23 11:49:37 +08:00
|
|
|
|
|
|
|
// LLVM only supports 0 and 2, make sure that we pass along that
|
|
|
|
// as a boolean.
|
|
|
|
Value *Ty = EmitScalarExpr(E->getArg(1));
|
|
|
|
ConstantInt *CI = dyn_cast<ConstantInt>(Ty);
|
|
|
|
assert(CI);
|
|
|
|
uint64_t val = CI->getZExtValue();
|
|
|
|
CI = ConstantInt::get(llvm::Type::getInt1Ty(VMContext), (val & 0x2) >> 1);
|
|
|
|
|
2009-10-28 06:09:17 +08:00
|
|
|
Value *F = CGM.getIntrinsic(Intrinsic::objectsize, ResType, 1);
|
|
|
|
return RValue::get(Builder.CreateCall2(F,
|
|
|
|
EmitScalarExpr(E->getArg(0)),
|
2009-12-23 11:49:37 +08:00
|
|
|
CI));
|
2008-09-04 05:13:56 +08:00
|
|
|
}
|
2008-07-22 06:59:13 +08:00
|
|
|
case Builtin::BI__builtin_prefetch: {
|
|
|
|
Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0));
|
|
|
|
// FIXME: Technically these constants should of type 'int', yes?
|
2009-09-09 23:08:12 +08:00
|
|
|
RW = (E->getNumArgs() > 1) ? EmitScalarExpr(E->getArg(1)) :
|
2009-08-14 05:57:51 +08:00
|
|
|
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0);
|
2009-09-09 23:08:12 +08:00
|
|
|
Locality = (E->getNumArgs() > 2) ? EmitScalarExpr(E->getArg(2)) :
|
2009-08-14 05:57:51 +08:00
|
|
|
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 3);
|
2008-07-22 06:59:13 +08:00
|
|
|
Value *F = CGM.getIntrinsic(Intrinsic::prefetch, 0, 0);
|
|
|
|
return RValue::get(Builder.CreateCall3(F, Address, RW, Locality));
|
|
|
|
}
|
|
|
|
case Builtin::BI__builtin_trap: {
|
|
|
|
Value *F = CGM.getIntrinsic(Intrinsic::trap, 0, 0);
|
|
|
|
return RValue::get(Builder.CreateCall(F));
|
2007-12-03 05:58:10 +08:00
|
|
|
}
|
2009-09-21 11:09:59 +08:00
|
|
|
case Builtin::BI__builtin_unreachable: {
|
2009-12-16 11:07:12 +08:00
|
|
|
if (CatchUndefined && HaveInsertPoint())
|
|
|
|
EmitBranch(getTrapBB());
|
2009-09-21 11:09:59 +08:00
|
|
|
Value *V = Builder.CreateUnreachable();
|
|
|
|
Builder.ClearInsertionPoint();
|
|
|
|
return RValue::get(V);
|
|
|
|
}
|
|
|
|
|
2008-07-22 02:44:41 +08:00
|
|
|
case Builtin::BI__builtin_powi:
|
|
|
|
case Builtin::BI__builtin_powif:
|
|
|
|
case Builtin::BI__builtin_powil: {
|
|
|
|
Value *Base = EmitScalarExpr(E->getArg(0));
|
|
|
|
Value *Exponent = EmitScalarExpr(E->getArg(1));
|
|
|
|
const llvm::Type *ArgType = Base->getType();
|
|
|
|
Value *F = CGM.getIntrinsic(Intrinsic::powi, &ArgType, 1);
|
|
|
|
return RValue::get(Builder.CreateCall2(F, Base, Exponent, "tmp"));
|
|
|
|
}
|
|
|
|
|
2007-12-20 08:44:32 +08:00
|
|
|
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: {
|
|
|
|
// Ordered comparisons: we know the arguments to these are matching scalar
|
|
|
|
// floating point values.
|
2009-09-09 23:08:12 +08:00
|
|
|
Value *LHS = EmitScalarExpr(E->getArg(0));
|
2007-12-20 08:44:32 +08:00
|
|
|
Value *RHS = EmitScalarExpr(E->getArg(1));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-12-20 08:44:32 +08:00
|
|
|
switch (BuiltinID) {
|
|
|
|
default: assert(0 && "Unknown ordered comparison");
|
|
|
|
case Builtin::BI__builtin_isgreater:
|
|
|
|
LHS = Builder.CreateFCmpOGT(LHS, RHS, "cmp");
|
|
|
|
break;
|
|
|
|
case Builtin::BI__builtin_isgreaterequal:
|
|
|
|
LHS = Builder.CreateFCmpOGE(LHS, RHS, "cmp");
|
|
|
|
break;
|
|
|
|
case Builtin::BI__builtin_isless:
|
|
|
|
LHS = Builder.CreateFCmpOLT(LHS, RHS, "cmp");
|
|
|
|
break;
|
|
|
|
case Builtin::BI__builtin_islessequal:
|
|
|
|
LHS = Builder.CreateFCmpOLE(LHS, RHS, "cmp");
|
|
|
|
break;
|
|
|
|
case Builtin::BI__builtin_islessgreater:
|
|
|
|
LHS = Builder.CreateFCmpONE(LHS, RHS, "cmp");
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
case Builtin::BI__builtin_isunordered:
|
2007-12-20 08:44:32 +08:00
|
|
|
LHS = Builder.CreateFCmpUNO(LHS, RHS, "cmp");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// ZExt bool to int type.
|
|
|
|
return RValue::get(Builder.CreateZExt(LHS, ConvertType(E->getType()),
|
|
|
|
"tmp"));
|
|
|
|
}
|
2009-09-01 12:19:44 +08:00
|
|
|
case Builtin::BI__builtin_isnan: {
|
|
|
|
Value *V = EmitScalarExpr(E->getArg(0));
|
|
|
|
V = Builder.CreateFCmpUNO(V, V, "cmp");
|
|
|
|
return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()), "tmp"));
|
|
|
|
}
|
2010-05-06 13:35:16 +08:00
|
|
|
|
|
|
|
case Builtin::BI__builtin_isinf: {
|
|
|
|
// isinf(x) --> fabs(x) == infinity
|
|
|
|
Value *V = EmitScalarExpr(E->getArg(0));
|
|
|
|
V = EmitFAbs(*this, V, E->getArg(0)->getType());
|
|
|
|
|
|
|
|
V = Builder.CreateFCmpOEQ(V, ConstantFP::getInfinity(V->getType()),"isinf");
|
|
|
|
return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()), "tmp"));
|
|
|
|
}
|
2010-05-06 14:13:53 +08:00
|
|
|
|
|
|
|
// TODO: BI__builtin_isinf_sign
|
|
|
|
// isinf_sign(x) -> isinf(x) ? (signbit(x) ? -1 : 1) : 0
|
2010-05-19 19:24:26 +08:00
|
|
|
|
|
|
|
case Builtin::BI__builtin_isnormal: {
|
|
|
|
// isnormal(x) --> x == x && fabsf(x) < infinity && fabsf(x) >= float_min
|
|
|
|
Value *V = EmitScalarExpr(E->getArg(0));
|
|
|
|
Value *Eq = Builder.CreateFCmpOEQ(V, V, "iseq");
|
|
|
|
|
|
|
|
Value *Abs = EmitFAbs(*this, V, E->getArg(0)->getType());
|
|
|
|
Value *IsLessThanInf =
|
|
|
|
Builder.CreateFCmpULT(Abs, ConstantFP::getInfinity(V->getType()),"isinf");
|
|
|
|
APFloat Smallest = APFloat::getSmallestNormalized(
|
|
|
|
getContext().getFloatTypeSemantics(E->getArg(0)->getType()));
|
|
|
|
Value *IsNormal =
|
|
|
|
Builder.CreateFCmpUGE(Abs, ConstantFP::get(V->getContext(), Smallest),
|
|
|
|
"isnormal");
|
|
|
|
V = Builder.CreateAnd(Eq, IsLessThanInf, "and");
|
|
|
|
V = Builder.CreateAnd(V, IsNormal, "and");
|
|
|
|
return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType())));
|
|
|
|
}
|
|
|
|
|
2010-05-06 14:04:13 +08:00
|
|
|
case Builtin::BI__builtin_isfinite: {
|
|
|
|
// isfinite(x) --> x == x && fabs(x) != infinity; }
|
|
|
|
Value *V = EmitScalarExpr(E->getArg(0));
|
|
|
|
Value *Eq = Builder.CreateFCmpOEQ(V, V, "iseq");
|
|
|
|
|
|
|
|
Value *Abs = EmitFAbs(*this, V, E->getArg(0)->getType());
|
|
|
|
Value *IsNotInf =
|
|
|
|
Builder.CreateFCmpUNE(Abs, ConstantFP::getInfinity(V->getType()),"isinf");
|
|
|
|
|
|
|
|
V = Builder.CreateAnd(Eq, IsNotInf, "and");
|
|
|
|
return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType())));
|
|
|
|
}
|
|
|
|
|
2009-06-02 15:10:30 +08:00
|
|
|
case Builtin::BIalloca:
|
2008-06-17 01:15:14 +08:00
|
|
|
case Builtin::BI__builtin_alloca: {
|
|
|
|
// FIXME: LLVM IR Should allow alloca with an i64 size!
|
|
|
|
Value *Size = EmitScalarExpr(E->getArg(0));
|
2009-08-14 05:57:51 +08:00
|
|
|
Size = Builder.CreateIntCast(Size, llvm::Type::getInt32Ty(VMContext), false, "tmp");
|
|
|
|
return RValue::get(Builder.CreateAlloca(llvm::Type::getInt8Ty(VMContext), Size, "tmp"));
|
2008-07-22 08:26:45 +08:00
|
|
|
}
|
2010-01-24 03:00:10 +08:00
|
|
|
case Builtin::BIbzero:
|
2008-07-22 08:26:45 +08:00
|
|
|
case Builtin::BI__builtin_bzero: {
|
|
|
|
Value *Address = EmitScalarExpr(E->getArg(0));
|
2010-04-04 11:10:52 +08:00
|
|
|
Value *SizeVal = EmitScalarExpr(E->getArg(1));
|
|
|
|
Builder.CreateCall5(CGM.getMemSetFn(Address->getType(), SizeVal->getType()),
|
|
|
|
Address,
|
|
|
|
llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 0),
|
|
|
|
SizeVal,
|
|
|
|
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1),
|
|
|
|
llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), 0));
|
2008-07-22 08:26:45 +08:00
|
|
|
return RValue::get(Address);
|
2008-06-17 01:15:14 +08:00
|
|
|
}
|
2009-12-17 08:14:28 +08:00
|
|
|
case Builtin::BImemcpy:
|
2008-05-20 07:27:48 +08:00
|
|
|
case Builtin::BI__builtin_memcpy: {
|
2008-07-22 08:26:45 +08:00
|
|
|
Value *Address = EmitScalarExpr(E->getArg(0));
|
2010-04-04 11:10:52 +08:00
|
|
|
Value *SrcAddr = EmitScalarExpr(E->getArg(1));
|
|
|
|
Value *SizeVal = EmitScalarExpr(E->getArg(2));
|
|
|
|
Builder.CreateCall5(CGM.getMemCpyFn(Address->getType(), SrcAddr->getType(),
|
|
|
|
SizeVal->getType()),
|
|
|
|
Address, SrcAddr, SizeVal,
|
|
|
|
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1),
|
|
|
|
llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), 0));
|
2008-07-22 08:26:45 +08:00
|
|
|
return RValue::get(Address);
|
|
|
|
}
|
2009-12-17 08:14:28 +08:00
|
|
|
case Builtin::BImemmove:
|
2008-07-22 08:26:45 +08:00
|
|
|
case Builtin::BI__builtin_memmove: {
|
|
|
|
Value *Address = EmitScalarExpr(E->getArg(0));
|
2010-04-04 11:10:52 +08:00
|
|
|
Value *SrcAddr = EmitScalarExpr(E->getArg(1));
|
|
|
|
Value *SizeVal = EmitScalarExpr(E->getArg(2));
|
|
|
|
Builder.CreateCall5(CGM.getMemMoveFn(Address->getType(), SrcAddr->getType(),
|
|
|
|
SizeVal->getType()),
|
|
|
|
Address, SrcAddr, SizeVal,
|
|
|
|
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1),
|
|
|
|
llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), 0));
|
2008-07-22 08:26:45 +08:00
|
|
|
return RValue::get(Address);
|
|
|
|
}
|
2009-12-17 08:14:28 +08:00
|
|
|
case Builtin::BImemset:
|
2008-07-22 08:26:45 +08:00
|
|
|
case Builtin::BI__builtin_memset: {
|
|
|
|
Value *Address = EmitScalarExpr(E->getArg(0));
|
2010-04-04 11:10:52 +08:00
|
|
|
Value *SizeVal = EmitScalarExpr(E->getArg(2));
|
|
|
|
Builder.CreateCall5(CGM.getMemSetFn(Address->getType(), SizeVal->getType()),
|
|
|
|
Address,
|
|
|
|
Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)),
|
|
|
|
llvm::Type::getInt8Ty(VMContext)),
|
|
|
|
SizeVal,
|
|
|
|
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1),
|
|
|
|
llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), 0));
|
2008-07-22 08:26:45 +08:00
|
|
|
return RValue::get(Address);
|
2008-05-20 07:27:48 +08:00
|
|
|
}
|
2010-03-03 18:30:05 +08:00
|
|
|
case Builtin::BI__builtin_dwarf_cfa: {
|
|
|
|
// The offset in bytes from the first argument to the CFA.
|
|
|
|
//
|
|
|
|
// Why on earth is this in the frontend? Is there any reason at
|
|
|
|
// all that the backend can't reasonably determine this while
|
|
|
|
// lowering llvm.eh.dwarf.cfa()?
|
|
|
|
//
|
|
|
|
// TODO: If there's a satisfactory reason, add a target hook for
|
|
|
|
// this instead of hard-coding 0, which is correct for most targets.
|
|
|
|
int32_t Offset = 0;
|
|
|
|
|
|
|
|
Value *F = CGM.getIntrinsic(Intrinsic::eh_dwarf_cfa, 0, 0);
|
|
|
|
return RValue::get(Builder.CreateCall(F, getInt32(VMContext, Offset)));
|
|
|
|
}
|
2008-05-20 16:59:34 +08:00
|
|
|
case Builtin::BI__builtin_return_address: {
|
2009-12-27 22:27:22 +08:00
|
|
|
Value *Depth = EmitScalarExpr(E->getArg(0));
|
|
|
|
Depth = Builder.CreateIntCast(Depth,
|
|
|
|
llvm::Type::getInt32Ty(VMContext),
|
|
|
|
false, "tmp");
|
2008-05-20 16:59:34 +08:00
|
|
|
Value *F = CGM.getIntrinsic(Intrinsic::returnaddress, 0, 0);
|
2009-12-27 22:27:22 +08:00
|
|
|
return RValue::get(Builder.CreateCall(F, Depth));
|
2008-05-20 16:59:34 +08:00
|
|
|
}
|
|
|
|
case Builtin::BI__builtin_frame_address: {
|
2009-12-27 22:27:22 +08:00
|
|
|
Value *Depth = EmitScalarExpr(E->getArg(0));
|
|
|
|
Depth = Builder.CreateIntCast(Depth,
|
|
|
|
llvm::Type::getInt32Ty(VMContext),
|
|
|
|
false, "tmp");
|
2008-05-20 16:59:34 +08:00
|
|
|
Value *F = CGM.getIntrinsic(Intrinsic::frameaddress, 0, 0);
|
2009-12-27 22:27:22 +08:00
|
|
|
return RValue::get(Builder.CreateCall(F, Depth));
|
2008-05-20 16:59:34 +08:00
|
|
|
}
|
2009-05-04 03:23:23 +08:00
|
|
|
case Builtin::BI__builtin_extract_return_addr: {
|
2010-03-03 12:15:11 +08:00
|
|
|
Value *Address = EmitScalarExpr(E->getArg(0));
|
|
|
|
Value *Result = getTargetHooks().decodeReturnAddress(*this, Address);
|
|
|
|
return RValue::get(Result);
|
|
|
|
}
|
|
|
|
case Builtin::BI__builtin_frob_return_addr: {
|
|
|
|
Value *Address = EmitScalarExpr(E->getArg(0));
|
|
|
|
Value *Result = getTargetHooks().encodeReturnAddress(*this, Address);
|
|
|
|
return RValue::get(Result);
|
2009-05-04 03:23:23 +08:00
|
|
|
}
|
2010-03-06 08:35:14 +08:00
|
|
|
case Builtin::BI__builtin_dwarf_sp_column: {
|
|
|
|
const llvm::IntegerType *Ty
|
|
|
|
= cast<llvm::IntegerType>(ConvertType(E->getType()));
|
|
|
|
int Column = getTargetHooks().getDwarfEHStackPointer(CGM);
|
|
|
|
if (Column == -1) {
|
|
|
|
CGM.ErrorUnsupported(E, "__builtin_dwarf_sp_column");
|
|
|
|
return RValue::get(llvm::UndefValue::get(Ty));
|
|
|
|
}
|
|
|
|
return RValue::get(llvm::ConstantInt::get(Ty, Column, true));
|
|
|
|
}
|
|
|
|
case Builtin::BI__builtin_init_dwarf_reg_size_table: {
|
|
|
|
Value *Address = EmitScalarExpr(E->getArg(0));
|
|
|
|
if (getTargetHooks().initDwarfEHRegSizeTable(*this, Address))
|
|
|
|
CGM.ErrorUnsupported(E, "__builtin_init_dwarf_reg_size_table");
|
|
|
|
return RValue::get(llvm::UndefValue::get(ConvertType(E->getType())));
|
|
|
|
}
|
2010-03-03 13:38:58 +08:00
|
|
|
case Builtin::BI__builtin_eh_return: {
|
|
|
|
Value *Int = EmitScalarExpr(E->getArg(0));
|
|
|
|
Value *Ptr = EmitScalarExpr(E->getArg(1));
|
|
|
|
|
|
|
|
const llvm::IntegerType *IntTy = cast<llvm::IntegerType>(Int->getType());
|
|
|
|
assert((IntTy->getBitWidth() == 32 || IntTy->getBitWidth() == 64) &&
|
|
|
|
"LLVM's __builtin_eh_return only supports 32- and 64-bit variants");
|
|
|
|
Value *F = CGM.getIntrinsic(IntTy->getBitWidth() == 32
|
|
|
|
? Intrinsic::eh_return_i32
|
|
|
|
: Intrinsic::eh_return_i64,
|
|
|
|
0, 0);
|
|
|
|
Builder.CreateCall2(F, Int, Ptr);
|
|
|
|
Value *V = Builder.CreateUnreachable();
|
|
|
|
Builder.ClearInsertionPoint();
|
|
|
|
return RValue::get(V);
|
|
|
|
}
|
2009-06-02 17:37:50 +08:00
|
|
|
case Builtin::BI__builtin_unwind_init: {
|
|
|
|
Value *F = CGM.getIntrinsic(Intrinsic::eh_unwind_init, 0, 0);
|
|
|
|
return RValue::get(Builder.CreateCall(F));
|
|
|
|
}
|
2010-03-02 10:31:24 +08:00
|
|
|
case Builtin::BI__builtin_extend_pointer: {
|
|
|
|
// Extends a pointer to the size of an _Unwind_Word, which is
|
2010-03-02 11:50:12 +08:00
|
|
|
// uint64_t on all platforms. Generally this gets poked into a
|
|
|
|
// register and eventually used as an address, so if the
|
|
|
|
// addressing registers are wider than pointers and the platform
|
|
|
|
// doesn't implicitly ignore high-order bits when doing
|
|
|
|
// addressing, we need to make sure we zext / sext based on
|
|
|
|
// the platform's expectations.
|
2010-03-02 10:31:24 +08:00
|
|
|
//
|
|
|
|
// See: http://gcc.gnu.org/ml/gcc-bugs/2002-02/msg00237.html
|
2010-03-02 11:50:12 +08:00
|
|
|
|
|
|
|
LLVMContext &C = CGM.getLLVMContext();
|
|
|
|
|
|
|
|
// Cast the pointer to intptr_t.
|
2010-03-02 10:31:24 +08:00
|
|
|
Value *Ptr = EmitScalarExpr(E->getArg(0));
|
2010-03-02 11:50:12 +08:00
|
|
|
const llvm::IntegerType *IntPtrTy = CGM.getTargetData().getIntPtrType(C);
|
|
|
|
Value *Result = Builder.CreatePtrToInt(Ptr, IntPtrTy, "extend.cast");
|
|
|
|
|
|
|
|
// If that's 64 bits, we're done.
|
|
|
|
if (IntPtrTy->getBitWidth() == 64)
|
|
|
|
return RValue::get(Result);
|
|
|
|
|
|
|
|
// Otherwise, ask the codegen data what to do.
|
|
|
|
const llvm::IntegerType *Int64Ty = llvm::IntegerType::get(C, 64);
|
2010-03-03 12:15:11 +08:00
|
|
|
if (getTargetHooks().extendPointerWithSExt())
|
2010-03-02 11:50:12 +08:00
|
|
|
return RValue::get(Builder.CreateSExt(Result, Int64Ty, "extend.sext"));
|
|
|
|
else
|
|
|
|
return RValue::get(Builder.CreateZExt(Result, Int64Ty, "extend.zext"));
|
2010-03-02 10:31:24 +08:00
|
|
|
}
|
2009-06-02 17:37:50 +08:00
|
|
|
case Builtin::BI__builtin_setjmp: {
|
2010-05-28 02:47:06 +08:00
|
|
|
// Buffer is a void**.
|
2009-06-02 17:37:50 +08:00
|
|
|
Value *Buf = EmitScalarExpr(E->getArg(0));
|
2010-05-28 02:47:06 +08:00
|
|
|
|
|
|
|
// Store the frame pointer to the setjmp buffer.
|
2009-06-02 17:37:50 +08:00
|
|
|
Value *FrameAddr =
|
2010-05-28 02:47:06 +08:00
|
|
|
Builder.CreateCall(CGM.getIntrinsic(Intrinsic::frameaddress),
|
|
|
|
ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0));
|
2009-06-02 17:37:50 +08:00
|
|
|
Builder.CreateStore(FrameAddr, Buf);
|
2010-05-28 02:47:06 +08:00
|
|
|
|
|
|
|
// Call LLVM's EH setjmp, which is lightweight.
|
|
|
|
Value *F = CGM.getIntrinsic(Intrinsic::eh_sjlj_setjmp);
|
|
|
|
Buf = Builder.CreateBitCast(Buf, llvm::Type::getInt8PtrTy(VMContext));
|
2009-06-02 17:37:50 +08:00
|
|
|
return RValue::get(Builder.CreateCall(F, Buf));
|
|
|
|
}
|
|
|
|
case Builtin::BI__builtin_longjmp: {
|
|
|
|
Value *Buf = EmitScalarExpr(E->getArg(0));
|
2010-05-28 02:47:06 +08:00
|
|
|
Buf = Builder.CreateBitCast(Buf, llvm::Type::getInt8PtrTy(VMContext));
|
|
|
|
|
|
|
|
// Call LLVM's EH longjmp, which is lightweight.
|
|
|
|
Builder.CreateCall(CGM.getIntrinsic(Intrinsic::eh_sjlj_longjmp), Buf);
|
|
|
|
|
|
|
|
// longjmp doesn't return; mark this as unreachable
|
|
|
|
Value *V = Builder.CreateUnreachable();
|
|
|
|
Builder.ClearInsertionPoint();
|
|
|
|
return RValue::get(V);
|
2009-06-02 17:37:50 +08:00
|
|
|
}
|
2008-05-10 06:40:52 +08:00
|
|
|
case Builtin::BI__sync_fetch_and_add:
|
|
|
|
case Builtin::BI__sync_fetch_and_sub:
|
2009-05-08 14:58:22 +08:00
|
|
|
case Builtin::BI__sync_fetch_and_or:
|
|
|
|
case Builtin::BI__sync_fetch_and_and:
|
|
|
|
case Builtin::BI__sync_fetch_and_xor:
|
|
|
|
case Builtin::BI__sync_add_and_fetch:
|
|
|
|
case Builtin::BI__sync_sub_and_fetch:
|
|
|
|
case Builtin::BI__sync_and_and_fetch:
|
|
|
|
case Builtin::BI__sync_or_and_fetch:
|
|
|
|
case Builtin::BI__sync_xor_and_fetch:
|
|
|
|
case Builtin::BI__sync_val_compare_and_swap:
|
|
|
|
case Builtin::BI__sync_bool_compare_and_swap:
|
|
|
|
case Builtin::BI__sync_lock_test_and_set:
|
|
|
|
case Builtin::BI__sync_lock_release:
|
|
|
|
assert(0 && "Shouldn't make it through sema");
|
|
|
|
case Builtin::BI__sync_fetch_and_add_1:
|
|
|
|
case Builtin::BI__sync_fetch_and_add_2:
|
|
|
|
case Builtin::BI__sync_fetch_and_add_4:
|
|
|
|
case Builtin::BI__sync_fetch_and_add_8:
|
|
|
|
case Builtin::BI__sync_fetch_and_add_16:
|
|
|
|
return EmitBinaryAtomic(*this, Intrinsic::atomic_load_add, E);
|
|
|
|
case Builtin::BI__sync_fetch_and_sub_1:
|
|
|
|
case Builtin::BI__sync_fetch_and_sub_2:
|
|
|
|
case Builtin::BI__sync_fetch_and_sub_4:
|
|
|
|
case Builtin::BI__sync_fetch_and_sub_8:
|
|
|
|
case Builtin::BI__sync_fetch_and_sub_16:
|
2008-06-25 16:21:36 +08:00
|
|
|
return EmitBinaryAtomic(*this, Intrinsic::atomic_load_sub, E);
|
2009-05-08 14:58:22 +08:00
|
|
|
case Builtin::BI__sync_fetch_and_or_1:
|
|
|
|
case Builtin::BI__sync_fetch_and_or_2:
|
|
|
|
case Builtin::BI__sync_fetch_and_or_4:
|
|
|
|
case Builtin::BI__sync_fetch_and_or_8:
|
|
|
|
case Builtin::BI__sync_fetch_and_or_16:
|
|
|
|
return EmitBinaryAtomic(*this, Intrinsic::atomic_load_or, E);
|
|
|
|
case Builtin::BI__sync_fetch_and_and_1:
|
|
|
|
case Builtin::BI__sync_fetch_and_and_2:
|
|
|
|
case Builtin::BI__sync_fetch_and_and_4:
|
|
|
|
case Builtin::BI__sync_fetch_and_and_8:
|
|
|
|
case Builtin::BI__sync_fetch_and_and_16:
|
|
|
|
return EmitBinaryAtomic(*this, Intrinsic::atomic_load_and, E);
|
|
|
|
case Builtin::BI__sync_fetch_and_xor_1:
|
|
|
|
case Builtin::BI__sync_fetch_and_xor_2:
|
|
|
|
case Builtin::BI__sync_fetch_and_xor_4:
|
|
|
|
case Builtin::BI__sync_fetch_and_xor_8:
|
|
|
|
case Builtin::BI__sync_fetch_and_xor_16:
|
|
|
|
return EmitBinaryAtomic(*this, Intrinsic::atomic_load_xor, E);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-08 14:58:22 +08:00
|
|
|
// Clang extensions: not overloaded yet.
|
2008-05-10 06:40:52 +08:00
|
|
|
case Builtin::BI__sync_fetch_and_min:
|
|
|
|
return EmitBinaryAtomic(*this, Intrinsic::atomic_load_min, E);
|
|
|
|
case Builtin::BI__sync_fetch_and_max:
|
|
|
|
return EmitBinaryAtomic(*this, Intrinsic::atomic_load_max, E);
|
|
|
|
case Builtin::BI__sync_fetch_and_umin:
|
|
|
|
return EmitBinaryAtomic(*this, Intrinsic::atomic_load_umin, E);
|
|
|
|
case Builtin::BI__sync_fetch_and_umax:
|
|
|
|
return EmitBinaryAtomic(*this, Intrinsic::atomic_load_umax, E);
|
2009-04-07 08:55:51 +08:00
|
|
|
|
2009-05-08 14:58:22 +08:00
|
|
|
case Builtin::BI__sync_add_and_fetch_1:
|
|
|
|
case Builtin::BI__sync_add_and_fetch_2:
|
|
|
|
case Builtin::BI__sync_add_and_fetch_4:
|
|
|
|
case Builtin::BI__sync_add_and_fetch_8:
|
|
|
|
case Builtin::BI__sync_add_and_fetch_16:
|
2009-09-09 23:08:12 +08:00
|
|
|
return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_add, E,
|
2009-04-07 08:55:51 +08:00
|
|
|
llvm::Instruction::Add);
|
2009-05-08 14:58:22 +08:00
|
|
|
case Builtin::BI__sync_sub_and_fetch_1:
|
|
|
|
case Builtin::BI__sync_sub_and_fetch_2:
|
|
|
|
case Builtin::BI__sync_sub_and_fetch_4:
|
|
|
|
case Builtin::BI__sync_sub_and_fetch_8:
|
|
|
|
case Builtin::BI__sync_sub_and_fetch_16:
|
2009-04-07 08:55:51 +08:00
|
|
|
return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_sub, E,
|
|
|
|
llvm::Instruction::Sub);
|
2009-05-08 14:58:22 +08:00
|
|
|
case Builtin::BI__sync_and_and_fetch_1:
|
|
|
|
case Builtin::BI__sync_and_and_fetch_2:
|
|
|
|
case Builtin::BI__sync_and_and_fetch_4:
|
|
|
|
case Builtin::BI__sync_and_and_fetch_8:
|
|
|
|
case Builtin::BI__sync_and_and_fetch_16:
|
2009-04-07 08:55:51 +08:00
|
|
|
return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_and, E,
|
|
|
|
llvm::Instruction::And);
|
2009-05-08 14:58:22 +08:00
|
|
|
case Builtin::BI__sync_or_and_fetch_1:
|
|
|
|
case Builtin::BI__sync_or_and_fetch_2:
|
|
|
|
case Builtin::BI__sync_or_and_fetch_4:
|
|
|
|
case Builtin::BI__sync_or_and_fetch_8:
|
|
|
|
case Builtin::BI__sync_or_and_fetch_16:
|
2009-04-07 08:55:51 +08:00
|
|
|
return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_or, E,
|
|
|
|
llvm::Instruction::Or);
|
2009-05-08 14:58:22 +08:00
|
|
|
case Builtin::BI__sync_xor_and_fetch_1:
|
|
|
|
case Builtin::BI__sync_xor_and_fetch_2:
|
|
|
|
case Builtin::BI__sync_xor_and_fetch_4:
|
|
|
|
case Builtin::BI__sync_xor_and_fetch_8:
|
|
|
|
case Builtin::BI__sync_xor_and_fetch_16:
|
2009-04-07 08:55:51 +08:00
|
|
|
return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_xor, E,
|
|
|
|
llvm::Instruction::Xor);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-08 14:58:22 +08:00
|
|
|
case Builtin::BI__sync_val_compare_and_swap_1:
|
|
|
|
case Builtin::BI__sync_val_compare_and_swap_2:
|
|
|
|
case Builtin::BI__sync_val_compare_and_swap_4:
|
|
|
|
case Builtin::BI__sync_val_compare_and_swap_8:
|
2010-03-20 15:04:11 +08:00
|
|
|
case Builtin::BI__sync_val_compare_and_swap_16: {
|
2008-07-31 11:28:23 +08:00
|
|
|
const llvm::Type *ResType[2];
|
|
|
|
ResType[0]= ConvertType(E->getType());
|
|
|
|
ResType[1] = ConvertType(E->getArg(0)->getType());
|
|
|
|
Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, ResType, 2);
|
2010-03-20 15:04:11 +08:00
|
|
|
Value *Args[3] = { EmitScalarExpr(E->getArg(0)),
|
|
|
|
EmitScalarExpr(E->getArg(1)),
|
|
|
|
EmitScalarExpr(E->getArg(2)) };
|
|
|
|
return RValue::get(EmitCallWithBarrier(*this, AtomF, Args, Args + 3));
|
2007-08-21 02:05:56 +08:00
|
|
|
}
|
2009-04-07 08:55:51 +08:00
|
|
|
|
2009-05-08 14:58:22 +08:00
|
|
|
case Builtin::BI__sync_bool_compare_and_swap_1:
|
|
|
|
case Builtin::BI__sync_bool_compare_and_swap_2:
|
|
|
|
case Builtin::BI__sync_bool_compare_and_swap_4:
|
|
|
|
case Builtin::BI__sync_bool_compare_and_swap_8:
|
2010-03-20 15:04:11 +08:00
|
|
|
case Builtin::BI__sync_bool_compare_and_swap_16: {
|
2009-04-07 08:55:51 +08:00
|
|
|
const llvm::Type *ResType[2];
|
2009-05-08 14:58:22 +08:00
|
|
|
ResType[0]= ConvertType(E->getArg(1)->getType());
|
2009-07-30 06:16:19 +08:00
|
|
|
ResType[1] = llvm::PointerType::getUnqual(ResType[0]);
|
2009-04-07 08:55:51 +08:00
|
|
|
Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, ResType, 2);
|
|
|
|
Value *OldVal = EmitScalarExpr(E->getArg(1));
|
2010-03-20 15:04:11 +08:00
|
|
|
Value *Args[3] = { EmitScalarExpr(E->getArg(0)),
|
|
|
|
OldVal,
|
|
|
|
EmitScalarExpr(E->getArg(2)) };
|
|
|
|
Value *PrevVal = EmitCallWithBarrier(*this, AtomF, Args, Args + 3);
|
2009-04-07 08:55:51 +08:00
|
|
|
Value *Result = Builder.CreateICmpEQ(PrevVal, OldVal);
|
|
|
|
// zext bool to int.
|
|
|
|
return RValue::get(Builder.CreateZExt(Result, ConvertType(E->getType())));
|
|
|
|
}
|
|
|
|
|
2009-05-08 14:58:22 +08:00
|
|
|
case Builtin::BI__sync_lock_test_and_set_1:
|
|
|
|
case Builtin::BI__sync_lock_test_and_set_2:
|
|
|
|
case Builtin::BI__sync_lock_test_and_set_4:
|
|
|
|
case Builtin::BI__sync_lock_test_and_set_8:
|
|
|
|
case Builtin::BI__sync_lock_test_and_set_16:
|
2008-05-15 15:38:03 +08:00
|
|
|
return EmitBinaryAtomic(*this, Intrinsic::atomic_swap, E);
|
2010-03-20 15:04:11 +08:00
|
|
|
|
2009-05-08 14:58:22 +08:00
|
|
|
case Builtin::BI__sync_lock_release_1:
|
|
|
|
case Builtin::BI__sync_lock_release_2:
|
|
|
|
case Builtin::BI__sync_lock_release_4:
|
|
|
|
case Builtin::BI__sync_lock_release_8:
|
2009-05-13 12:46:13 +08:00
|
|
|
case Builtin::BI__sync_lock_release_16: {
|
|
|
|
Value *Ptr = EmitScalarExpr(E->getArg(0));
|
|
|
|
const llvm::Type *ElTy =
|
|
|
|
cast<llvm::PointerType>(Ptr->getType())->getElementType();
|
2009-11-30 05:11:47 +08:00
|
|
|
llvm::StoreInst *Store =
|
|
|
|
Builder.CreateStore(llvm::Constant::getNullValue(ElTy), Ptr);
|
|
|
|
Store->setVolatile(true);
|
2009-05-28 07:45:33 +08:00
|
|
|
return RValue::get(0);
|
2009-05-13 12:46:13 +08:00
|
|
|
}
|
2009-02-17 06:43:43 +08:00
|
|
|
|
2009-05-13 12:46:13 +08:00
|
|
|
case Builtin::BI__sync_synchronize: {
|
2010-03-20 15:04:11 +08:00
|
|
|
// We assume like gcc appears to, that this only applies to cached memory.
|
|
|
|
EmitMemoryBarrier(*this, true, true, true, true, false);
|
2009-05-28 07:45:33 +08:00
|
|
|
return RValue::get(0);
|
2009-05-13 12:46:13 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-01-16 09:21:14 +08:00
|
|
|
case Builtin::BI__builtin_llvm_memory_barrier: {
|
|
|
|
Value *C[5] = {
|
|
|
|
EmitScalarExpr(E->getArg(0)),
|
|
|
|
EmitScalarExpr(E->getArg(1)),
|
|
|
|
EmitScalarExpr(E->getArg(2)),
|
|
|
|
EmitScalarExpr(E->getArg(3)),
|
|
|
|
EmitScalarExpr(E->getArg(4))
|
|
|
|
};
|
|
|
|
Builder.CreateCall(CGM.getIntrinsic(Intrinsic::memory_barrier), C, C + 5);
|
|
|
|
return RValue::get(0);
|
|
|
|
}
|
|
|
|
|
2009-02-17 06:43:43 +08:00
|
|
|
// Library functions with special handling.
|
|
|
|
case Builtin::BIsqrt:
|
|
|
|
case Builtin::BIsqrtf:
|
|
|
|
case Builtin::BIsqrtl: {
|
2010-04-07 16:20:20 +08:00
|
|
|
// TODO: there is currently no set of optimizer flags
|
|
|
|
// sufficient for us to rewrite sqrt to @llvm.sqrt.
|
|
|
|
// -fmath-errno=0 is not good enough; we need finiteness.
|
|
|
|
// We could probably precondition the call with an ult
|
|
|
|
// against 0, but is that worth the complexity?
|
|
|
|
break;
|
2009-02-17 06:43:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
case Builtin::BIpow:
|
|
|
|
case Builtin::BIpowf:
|
|
|
|
case Builtin::BIpowl: {
|
|
|
|
// Rewrite sqrt to intrinsic if allowed.
|
2009-06-30 10:34:44 +08:00
|
|
|
if (!FD->hasAttr<ConstAttr>())
|
2009-02-17 06:43:43 +08:00
|
|
|
break;
|
|
|
|
Value *Base = EmitScalarExpr(E->getArg(0));
|
|
|
|
Value *Exponent = EmitScalarExpr(E->getArg(1));
|
|
|
|
const llvm::Type *ArgType = Base->getType();
|
|
|
|
Value *F = CGM.getIntrinsic(Intrinsic::pow, &ArgType, 1);
|
|
|
|
return RValue::get(Builder.CreateCall2(F, Base, Exponent, "tmp"));
|
|
|
|
}
|
2010-03-06 10:17:52 +08:00
|
|
|
|
|
|
|
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));
|
|
|
|
const llvm::Type *ArgTy = Arg->getType();
|
|
|
|
if (ArgTy->isPPC_FP128Ty())
|
|
|
|
break; // FIXME: I'm not sure what the right implementation is here.
|
|
|
|
int ArgWidth = ArgTy->getPrimitiveSizeInBits();
|
|
|
|
const llvm::Type *ArgIntTy = llvm::IntegerType::get(C, ArgWidth);
|
|
|
|
Value *BCArg = Builder.CreateBitCast(Arg, ArgIntTy);
|
|
|
|
Value *ZeroCmp = llvm::Constant::getNullValue(ArgIntTy);
|
|
|
|
Value *Result = Builder.CreateICmpSLT(BCArg, ZeroCmp);
|
|
|
|
return RValue::get(Builder.CreateZExt(Result, ConvertType(E->getType())));
|
|
|
|
}
|
2008-05-15 15:38:03 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-01 02:32:54 +08:00
|
|
|
// If this is an alias for a libm function (e.g. __builtin_sin) turn it into
|
|
|
|
// that function.
|
Implicitly declare certain C library functions (malloc, strcpy, memmove,
etc.) when we perform name lookup on them. This ensures that we
produce the correct signature for these functions, which has two
practical impacts:
1) When we're supporting the "implicit function declaration" feature
of C99, these functions will be implicitly declared with the right
signature rather than as a function returning "int" with no
prototype. See PR3541 for the reason why this is important (hint:
GCC always predeclares these functions).
2) If users attempt to redeclare one of these library functions with
an incompatible signature, we produce a hard error.
This patch does a little bit of work to give reasonable error
messages. For example, when we hit case #1 we complain that we're
implicitly declaring this function with a specific signature, and then
we give a note that asks the user to include the appropriate header
(e.g., "please include <stdlib.h> or explicitly declare 'malloc'"). In
case #2, we show the type of the implicit builtin that was incorrectly
declared, so the user can see the problem. We could do better here:
for example, when displaying this latter error message we say
something like:
'strcpy' was implicitly declared here with type 'char *(char *, char
const *)'
but we should really print out a fake code line showing the
declaration, like this:
'strcpy' was implicitly declared here as:
char *strcpy(char *, char const *)
This would also be good for printing built-in candidates with C++
operator overloading.
The set of C library functions supported by this patch includes all
functions from the C99 specification's <stdlib.h> and <string.h> that
(a) are predefined by GCC and (b) have signatures that could cause
codegen issues if they are treated as functions with no prototype
returning and int. Future work could extend this set of functions to
other C library functions that we know about.
llvm-svn: 64504
2009-02-14 07:20:09 +08:00
|
|
|
if (getContext().BuiltinInfo.isLibFunction(BuiltinID) ||
|
|
|
|
getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID))
|
2009-12-25 03:08:58 +08:00
|
|
|
return EmitCall(E->getCallee()->getType(),
|
|
|
|
CGM.getBuiltinLibFunction(FD, BuiltinID),
|
2009-12-25 04:40:36 +08:00
|
|
|
ReturnValueSlot(),
|
2009-12-25 03:08:58 +08:00
|
|
|
E->arg_begin(), E->arg_end());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-01 02:32:54 +08:00
|
|
|
// See if we have a target specific intrinsic.
|
2009-02-05 09:50:47 +08:00
|
|
|
const char *Name = getContext().BuiltinInfo.GetName(BuiltinID);
|
2009-08-24 17:54:37 +08:00
|
|
|
Intrinsic::ID IntrinsicID = Intrinsic::not_intrinsic;
|
|
|
|
if (const char *Prefix =
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::Triple::getArchTypePrefix(Target.getTriple().getArch()))
|
2009-08-24 17:54:37 +08:00
|
|
|
IntrinsicID = Intrinsic::getIntrinsicForGCCBuiltin(Prefix, Name);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-01 02:32:54 +08:00
|
|
|
if (IntrinsicID != Intrinsic::not_intrinsic) {
|
|
|
|
SmallVector<Value*, 16> Args;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-01 02:32:54 +08:00
|
|
|
Function *F = CGM.getIntrinsic(IntrinsicID);
|
|
|
|
const llvm::FunctionType *FTy = F->getFunctionType();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-01 02:32:54 +08:00
|
|
|
for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
|
|
|
|
Value *ArgValue = EmitScalarExpr(E->getArg(i));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-01 02:32:54 +08:00
|
|
|
// If the intrinsic arg type is different from the builtin arg type
|
|
|
|
// we need to do a bit cast.
|
|
|
|
const llvm::Type *PTy = FTy->getParamType(i);
|
|
|
|
if (PTy != ArgValue->getType()) {
|
|
|
|
assert(PTy->canLosslesslyBitCastTo(FTy->getParamType(i)) &&
|
|
|
|
"Must be able to losslessly bit cast to param");
|
|
|
|
ArgValue = Builder.CreateBitCast(ArgValue, PTy);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-01 02:32:54 +08:00
|
|
|
Args.push_back(ArgValue);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-21 17:52:38 +08:00
|
|
|
Value *V = Builder.CreateCall(F, Args.data(), Args.data() + Args.size());
|
2008-07-01 02:32:54 +08:00
|
|
|
QualType BuiltinRetType = E->getType();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-14 05:57:51 +08:00
|
|
|
const llvm::Type *RetTy = llvm::Type::getVoidTy(VMContext);
|
2008-07-01 02:32:54 +08:00
|
|
|
if (!BuiltinRetType->isVoidType()) RetTy = ConvertType(BuiltinRetType);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-01 02:32:54 +08:00
|
|
|
if (RetTy != V->getType()) {
|
|
|
|
assert(V->getType()->canLosslesslyBitCastTo(RetTy) &&
|
|
|
|
"Must be able to losslessly bit cast result type");
|
|
|
|
V = Builder.CreateBitCast(V, RetTy);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-01 02:32:54 +08:00
|
|
|
return RValue::get(V);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-01 02:32:54 +08:00
|
|
|
// See if we have a target specific builtin that needs to be lowered.
|
2008-10-10 08:24:54 +08:00
|
|
|
if (Value *V = EmitTargetBuiltinExpr(BuiltinID, E))
|
2008-07-01 02:32:54 +08:00
|
|
|
return RValue::get(V);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-16 08:56:44 +08:00
|
|
|
ErrorUnsupported(E, "builtin function");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-01 02:32:54 +08:00
|
|
|
// Unknown builtin, for now just dump it out and return undef.
|
|
|
|
if (hasAggregateLLVMType(E->getType()))
|
2010-02-09 10:48:28 +08:00
|
|
|
return RValue::getAggregate(CreateMemTemp(E->getType()));
|
2009-07-31 07:11:26 +08:00
|
|
|
return RValue::get(llvm::UndefValue::get(ConvertType(E->getType())));
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2007-12-10 07:17:02 +08:00
|
|
|
|
2008-10-10 08:24:54 +08:00
|
|
|
Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID,
|
|
|
|
const CallExpr *E) {
|
2009-08-24 17:54:37 +08:00
|
|
|
switch (Target.getTriple().getArch()) {
|
2010-03-04 03:03:45 +08:00
|
|
|
case llvm::Triple::arm:
|
|
|
|
case llvm::Triple::thumb:
|
|
|
|
return EmitARMBuiltinExpr(BuiltinID, E);
|
2009-08-24 17:54:37 +08:00
|
|
|
case llvm::Triple::x86:
|
|
|
|
case llvm::Triple::x86_64:
|
2008-10-10 08:24:54 +08:00
|
|
|
return EmitX86BuiltinExpr(BuiltinID, E);
|
2009-08-24 17:54:37 +08:00
|
|
|
case llvm::Triple::ppc:
|
|
|
|
case llvm::Triple::ppc64:
|
2008-10-10 08:24:54 +08:00
|
|
|
return EmitPPCBuiltinExpr(BuiltinID, E);
|
2009-08-24 17:54:37 +08:00
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
2008-10-10 08:24:54 +08:00
|
|
|
}
|
|
|
|
|
2010-03-04 03:03:45 +08:00
|
|
|
Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
|
|
|
|
const CallExpr *E) {
|
|
|
|
switch (BuiltinID) {
|
|
|
|
default: return 0;
|
|
|
|
|
|
|
|
case ARM::BI__builtin_thread_pointer: {
|
|
|
|
Value *AtomF = CGM.getIntrinsic(Intrinsic::arm_thread_pointer, 0, 0);
|
|
|
|
return Builder.CreateCall(AtomF);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
|
2007-12-13 15:34:23 +08:00
|
|
|
const CallExpr *E) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-12-15 01:48:24 +08:00
|
|
|
llvm::SmallVector<Value*, 4> Ops;
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = E->getNumArgs(); i != e; i++)
|
|
|
|
Ops.push_back(EmitScalarExpr(E->getArg(i)));
|
|
|
|
|
2007-12-10 07:17:02 +08:00
|
|
|
switch (BuiltinID) {
|
2007-12-10 07:39:18 +08:00
|
|
|
default: return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
case X86::BI__builtin_ia32_pslldi128:
|
2008-04-14 12:49:57 +08:00
|
|
|
case X86::BI__builtin_ia32_psllqi128:
|
2009-09-09 23:08:12 +08:00
|
|
|
case X86::BI__builtin_ia32_psllwi128:
|
2008-04-14 12:49:57 +08:00
|
|
|
case X86::BI__builtin_ia32_psradi128:
|
|
|
|
case X86::BI__builtin_ia32_psrawi128:
|
|
|
|
case X86::BI__builtin_ia32_psrldi128:
|
|
|
|
case X86::BI__builtin_ia32_psrlqi128:
|
|
|
|
case X86::BI__builtin_ia32_psrlwi128: {
|
2009-08-14 05:57:51 +08:00
|
|
|
Ops[1] = Builder.CreateZExt(Ops[1], llvm::Type::getInt64Ty(VMContext), "zext");
|
|
|
|
const llvm::Type *Ty = llvm::VectorType::get(llvm::Type::getInt64Ty(VMContext), 2);
|
|
|
|
llvm::Value *Zero = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0);
|
2009-07-31 07:11:26 +08:00
|
|
|
Ops[1] = Builder.CreateInsertElement(llvm::UndefValue::get(Ty),
|
2008-04-14 12:49:57 +08:00
|
|
|
Ops[1], Zero, "insert");
|
|
|
|
Ops[1] = Builder.CreateBitCast(Ops[1], Ops[0]->getType(), "bitcast");
|
|
|
|
const char *name = 0;
|
|
|
|
Intrinsic::ID ID = Intrinsic::not_intrinsic;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-14 12:49:57 +08:00
|
|
|
switch (BuiltinID) {
|
|
|
|
default: assert(0 && "Unsupported shift intrinsic!");
|
|
|
|
case X86::BI__builtin_ia32_pslldi128:
|
|
|
|
name = "pslldi";
|
|
|
|
ID = Intrinsic::x86_sse2_psll_d;
|
|
|
|
break;
|
|
|
|
case X86::BI__builtin_ia32_psllqi128:
|
|
|
|
name = "psllqi";
|
|
|
|
ID = Intrinsic::x86_sse2_psll_q;
|
|
|
|
break;
|
|
|
|
case X86::BI__builtin_ia32_psllwi128:
|
|
|
|
name = "psllwi";
|
|
|
|
ID = Intrinsic::x86_sse2_psll_w;
|
|
|
|
break;
|
|
|
|
case X86::BI__builtin_ia32_psradi128:
|
|
|
|
name = "psradi";
|
|
|
|
ID = Intrinsic::x86_sse2_psra_d;
|
|
|
|
break;
|
|
|
|
case X86::BI__builtin_ia32_psrawi128:
|
|
|
|
name = "psrawi";
|
|
|
|
ID = Intrinsic::x86_sse2_psra_w;
|
|
|
|
break;
|
|
|
|
case X86::BI__builtin_ia32_psrldi128:
|
|
|
|
name = "psrldi";
|
|
|
|
ID = Intrinsic::x86_sse2_psrl_d;
|
|
|
|
break;
|
|
|
|
case X86::BI__builtin_ia32_psrlqi128:
|
|
|
|
name = "psrlqi";
|
|
|
|
ID = Intrinsic::x86_sse2_psrl_q;
|
|
|
|
break;
|
|
|
|
case X86::BI__builtin_ia32_psrlwi128:
|
|
|
|
name = "psrlwi";
|
|
|
|
ID = Intrinsic::x86_sse2_psrl_w;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
llvm::Function *F = CGM.getIntrinsic(ID);
|
2009-09-09 23:08:12 +08:00
|
|
|
return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name);
|
2008-04-14 12:49:57 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
case X86::BI__builtin_ia32_pslldi:
|
2007-12-15 01:48:24 +08:00
|
|
|
case X86::BI__builtin_ia32_psllqi:
|
2009-09-09 23:08:12 +08:00
|
|
|
case X86::BI__builtin_ia32_psllwi:
|
2007-12-15 01:48:24 +08:00
|
|
|
case X86::BI__builtin_ia32_psradi:
|
|
|
|
case X86::BI__builtin_ia32_psrawi:
|
|
|
|
case X86::BI__builtin_ia32_psrldi:
|
|
|
|
case X86::BI__builtin_ia32_psrlqi:
|
|
|
|
case X86::BI__builtin_ia32_psrlwi: {
|
2009-08-14 05:57:51 +08:00
|
|
|
Ops[1] = Builder.CreateZExt(Ops[1], llvm::Type::getInt64Ty(VMContext), "zext");
|
|
|
|
const llvm::Type *Ty = llvm::VectorType::get(llvm::Type::getInt64Ty(VMContext), 1);
|
2007-12-15 01:48:24 +08:00
|
|
|
Ops[1] = Builder.CreateBitCast(Ops[1], Ty, "bitcast");
|
|
|
|
const char *name = 0;
|
|
|
|
Intrinsic::ID ID = Intrinsic::not_intrinsic;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-12-15 01:48:24 +08:00
|
|
|
switch (BuiltinID) {
|
|
|
|
default: assert(0 && "Unsupported shift intrinsic!");
|
|
|
|
case X86::BI__builtin_ia32_pslldi:
|
|
|
|
name = "pslldi";
|
|
|
|
ID = Intrinsic::x86_mmx_psll_d;
|
|
|
|
break;
|
|
|
|
case X86::BI__builtin_ia32_psllqi:
|
|
|
|
name = "psllqi";
|
|
|
|
ID = Intrinsic::x86_mmx_psll_q;
|
|
|
|
break;
|
|
|
|
case X86::BI__builtin_ia32_psllwi:
|
|
|
|
name = "psllwi";
|
|
|
|
ID = Intrinsic::x86_mmx_psll_w;
|
|
|
|
break;
|
|
|
|
case X86::BI__builtin_ia32_psradi:
|
|
|
|
name = "psradi";
|
|
|
|
ID = Intrinsic::x86_mmx_psra_d;
|
|
|
|
break;
|
|
|
|
case X86::BI__builtin_ia32_psrawi:
|
|
|
|
name = "psrawi";
|
|
|
|
ID = Intrinsic::x86_mmx_psra_w;
|
|
|
|
break;
|
|
|
|
case X86::BI__builtin_ia32_psrldi:
|
|
|
|
name = "psrldi";
|
|
|
|
ID = Intrinsic::x86_mmx_psrl_d;
|
|
|
|
break;
|
|
|
|
case X86::BI__builtin_ia32_psrlqi:
|
|
|
|
name = "psrlqi";
|
|
|
|
ID = Intrinsic::x86_mmx_psrl_q;
|
|
|
|
break;
|
|
|
|
case X86::BI__builtin_ia32_psrlwi:
|
|
|
|
name = "psrlwi";
|
|
|
|
ID = Intrinsic::x86_mmx_psrl_w;
|
|
|
|
break;
|
|
|
|
}
|
2007-12-18 08:25:38 +08:00
|
|
|
llvm::Function *F = CGM.getIntrinsic(ID);
|
2009-09-09 23:08:12 +08:00
|
|
|
return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name);
|
2007-12-15 01:48:24 +08:00
|
|
|
}
|
2009-05-19 03:16:46 +08:00
|
|
|
case X86::BI__builtin_ia32_cmpps: {
|
|
|
|
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse_cmp_ps);
|
|
|
|
return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), "cmpps");
|
|
|
|
}
|
|
|
|
case X86::BI__builtin_ia32_cmpss: {
|
|
|
|
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse_cmp_ss);
|
|
|
|
return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), "cmpss");
|
2007-12-17 06:33:50 +08:00
|
|
|
}
|
2008-04-14 12:49:57 +08:00
|
|
|
case X86::BI__builtin_ia32_ldmxcsr: {
|
2009-10-13 18:07:13 +08:00
|
|
|
const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext);
|
2009-08-14 05:57:51 +08:00
|
|
|
Value *One = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1);
|
|
|
|
Value *Tmp = Builder.CreateAlloca(llvm::Type::getInt32Ty(VMContext), One, "tmp");
|
2008-04-14 12:49:57 +08:00
|
|
|
Builder.CreateStore(Ops[0], Tmp);
|
|
|
|
return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_ldmxcsr),
|
2008-05-06 08:56:42 +08:00
|
|
|
Builder.CreateBitCast(Tmp, PtrTy));
|
2008-04-14 12:49:57 +08:00
|
|
|
}
|
|
|
|
case X86::BI__builtin_ia32_stmxcsr: {
|
2009-10-13 18:07:13 +08:00
|
|
|
const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext);
|
2009-08-14 05:57:51 +08:00
|
|
|
Value *One = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1);
|
|
|
|
Value *Tmp = Builder.CreateAlloca(llvm::Type::getInt32Ty(VMContext), One, "tmp");
|
2008-04-14 12:49:57 +08:00
|
|
|
One = Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_stmxcsr),
|
2008-05-06 08:56:42 +08:00
|
|
|
Builder.CreateBitCast(Tmp, PtrTy));
|
2008-04-14 12:49:57 +08:00
|
|
|
return Builder.CreateLoad(Tmp, "stmxcsr");
|
|
|
|
}
|
2009-05-19 03:16:46 +08:00
|
|
|
case X86::BI__builtin_ia32_cmppd: {
|
|
|
|
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse2_cmp_pd);
|
|
|
|
return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), "cmppd");
|
|
|
|
}
|
|
|
|
case X86::BI__builtin_ia32_cmpsd: {
|
|
|
|
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse2_cmp_sd);
|
|
|
|
return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), "cmpsd");
|
2007-12-17 06:33:50 +08:00
|
|
|
}
|
2008-04-14 12:49:57 +08:00
|
|
|
case X86::BI__builtin_ia32_storehps:
|
|
|
|
case X86::BI__builtin_ia32_storelps: {
|
2009-08-14 05:57:51 +08:00
|
|
|
const llvm::Type *EltTy = llvm::Type::getInt64Ty(VMContext);
|
2009-07-30 06:16:19 +08:00
|
|
|
llvm::Type *PtrTy = llvm::PointerType::getUnqual(EltTy);
|
|
|
|
llvm::Type *VecTy = llvm::VectorType::get(EltTy, 2);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-14 12:49:57 +08:00
|
|
|
// cast val v2i64
|
|
|
|
Ops[1] = Builder.CreateBitCast(Ops[1], VecTy, "cast");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-14 12:49:57 +08:00
|
|
|
// extract (0, 1)
|
|
|
|
unsigned Index = BuiltinID == X86::BI__builtin_ia32_storelps ? 0 : 1;
|
2009-08-14 05:57:51 +08:00
|
|
|
llvm::Value *Idx = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Index);
|
2008-04-14 12:49:57 +08:00
|
|
|
Ops[1] = Builder.CreateExtractElement(Ops[1], Idx, "extract");
|
|
|
|
|
|
|
|
// cast pointer to i64 & store
|
|
|
|
Ops[0] = Builder.CreateBitCast(Ops[0], PtrTy);
|
|
|
|
return Builder.CreateStore(Ops[1], Ops[0]);
|
|
|
|
}
|
2009-12-01 13:00:51 +08:00
|
|
|
case X86::BI__builtin_ia32_palignr: {
|
2010-04-15 09:43:08 +08:00
|
|
|
unsigned shiftVal = cast<llvm::ConstantInt>(Ops[2])->getZExtValue();
|
|
|
|
|
|
|
|
// If palignr is shifting the pair of input vectors less than 9 bytes,
|
|
|
|
// emit a shuffle instruction.
|
|
|
|
if (shiftVal <= 8) {
|
|
|
|
const llvm::Type *IntTy = llvm::Type::getInt32Ty(VMContext);
|
|
|
|
|
|
|
|
llvm::SmallVector<llvm::Constant*, 8> Indices;
|
|
|
|
for (unsigned i = 0; i != 8; ++i)
|
|
|
|
Indices.push_back(llvm::ConstantInt::get(IntTy, shiftVal + i));
|
|
|
|
|
|
|
|
Value* SV = llvm::ConstantVector::get(Indices.begin(), Indices.size());
|
|
|
|
return Builder.CreateShuffleVector(Ops[1], Ops[0], SV, "palignr");
|
|
|
|
}
|
|
|
|
|
|
|
|
// If palignr is shifting the pair of input vectors more than 8 but less
|
|
|
|
// than 16 bytes, emit a logical right shift of the destination.
|
|
|
|
if (shiftVal < 16) {
|
|
|
|
// MMX has these as 1 x i64 vectors for some odd optimization reasons.
|
|
|
|
const llvm::Type *EltTy = llvm::Type::getInt64Ty(VMContext);
|
|
|
|
const llvm::Type *VecTy = llvm::VectorType::get(EltTy, 1);
|
|
|
|
|
|
|
|
Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast");
|
|
|
|
Ops[1] = llvm::ConstantInt::get(VecTy, (shiftVal-8) * 8);
|
|
|
|
|
|
|
|
// create i32 constant
|
|
|
|
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_mmx_psrl_q);
|
|
|
|
return Builder.CreateCall(F, &Ops[0], &Ops[0] + 2, "palignr");
|
|
|
|
}
|
|
|
|
|
|
|
|
// If palignr is shifting the pair of vectors more than 32 bytes, emit zero.
|
|
|
|
return llvm::Constant::getNullValue(ConvertType(E->getType()));
|
2009-12-14 13:15:02 +08:00
|
|
|
}
|
|
|
|
case X86::BI__builtin_ia32_palignr128: {
|
2009-12-14 12:57:03 +08:00
|
|
|
unsigned shiftVal = cast<llvm::ConstantInt>(Ops[2])->getZExtValue();
|
|
|
|
|
|
|
|
// If palignr is shifting the pair of input vectors less than 17 bytes,
|
|
|
|
// emit a shuffle instruction.
|
|
|
|
if (shiftVal <= 16) {
|
|
|
|
const llvm::Type *IntTy = llvm::Type::getInt32Ty(VMContext);
|
|
|
|
|
|
|
|
llvm::SmallVector<llvm::Constant*, 16> Indices;
|
|
|
|
for (unsigned i = 0; i != 16; ++i)
|
|
|
|
Indices.push_back(llvm::ConstantInt::get(IntTy, shiftVal + i));
|
|
|
|
|
|
|
|
Value* SV = llvm::ConstantVector::get(Indices.begin(), Indices.size());
|
|
|
|
return Builder.CreateShuffleVector(Ops[1], Ops[0], SV, "palignr");
|
|
|
|
}
|
|
|
|
|
|
|
|
// If palignr is shifting the pair of input vectors more than 16 but less
|
|
|
|
// than 32 bytes, emit a logical right shift of the destination.
|
|
|
|
if (shiftVal < 32) {
|
|
|
|
const llvm::Type *EltTy = llvm::Type::getInt64Ty(VMContext);
|
|
|
|
const llvm::Type *VecTy = llvm::VectorType::get(EltTy, 2);
|
|
|
|
const llvm::Type *IntTy = llvm::Type::getInt32Ty(VMContext);
|
|
|
|
|
|
|
|
Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast");
|
|
|
|
Ops[1] = llvm::ConstantInt::get(IntTy, (shiftVal-16) * 8);
|
|
|
|
|
|
|
|
// create i32 constant
|
|
|
|
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse2_psrl_dq);
|
|
|
|
return Builder.CreateCall(F, &Ops[0], &Ops[0] + 2, "palignr");
|
|
|
|
}
|
|
|
|
|
|
|
|
// If palignr is shifting the pair of vectors more than 32 bytes, emit zero.
|
|
|
|
return llvm::Constant::getNullValue(ConvertType(E->getType()));
|
2009-12-01 13:00:51 +08:00
|
|
|
}
|
2007-12-10 07:17:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
|
2007-12-13 15:34:23 +08:00
|
|
|
const CallExpr *E) {
|
2010-04-14 11:54:58 +08:00
|
|
|
llvm::SmallVector<Value*, 4> Ops;
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = E->getNumArgs(); i != e; i++)
|
|
|
|
Ops.push_back(EmitScalarExpr(E->getArg(i)));
|
|
|
|
|
|
|
|
Intrinsic::ID ID = Intrinsic::not_intrinsic;
|
|
|
|
|
|
|
|
switch (BuiltinID) {
|
|
|
|
default: return 0;
|
|
|
|
|
|
|
|
// vec_st
|
|
|
|
case PPC::BI__builtin_altivec_stvx:
|
|
|
|
case PPC::BI__builtin_altivec_stvxl:
|
|
|
|
case PPC::BI__builtin_altivec_stvebx:
|
|
|
|
case PPC::BI__builtin_altivec_stvehx:
|
|
|
|
case PPC::BI__builtin_altivec_stvewx:
|
|
|
|
{
|
|
|
|
Ops[2] = Builder.CreateBitCast(Ops[2], llvm::Type::getInt8PtrTy(VMContext));
|
|
|
|
Ops[1] = !isa<Constant>(Ops[1]) || !cast<Constant>(Ops[1])->isNullValue()
|
|
|
|
? Builder.CreateGEP(Ops[2], Ops[1], "tmp") : Ops[2];
|
|
|
|
Ops.pop_back();
|
|
|
|
|
|
|
|
switch (BuiltinID) {
|
|
|
|
default: assert(0 && "Unsupported vavg intrinsic!");
|
|
|
|
case PPC::BI__builtin_altivec_stvx:
|
|
|
|
ID = Intrinsic::ppc_altivec_stvx;
|
|
|
|
break;
|
|
|
|
case PPC::BI__builtin_altivec_stvxl:
|
|
|
|
ID = Intrinsic::ppc_altivec_stvxl;
|
|
|
|
break;
|
|
|
|
case PPC::BI__builtin_altivec_stvebx:
|
|
|
|
ID = Intrinsic::ppc_altivec_stvebx;
|
|
|
|
break;
|
|
|
|
case PPC::BI__builtin_altivec_stvehx:
|
|
|
|
ID = Intrinsic::ppc_altivec_stvehx;
|
|
|
|
break;
|
|
|
|
case PPC::BI__builtin_altivec_stvewx:
|
|
|
|
ID = Intrinsic::ppc_altivec_stvewx;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
llvm::Function *F = CGM.getIntrinsic(ID);
|
|
|
|
return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), "");
|
|
|
|
}
|
|
|
|
}
|
2009-12-19 04:58:47 +08:00
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|