Newer
Older
//===---- CGBuiltin.cpp - Emit LLVM Code for builtins ---------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This contains code to emit Builtin calls as LLVM code.
//
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "clang/Basic/TargetInfo.h"
Chris Lattner
committed
#include "clang/AST/ASTContext.h"
#include "clang/AST/Builtins.h"
#include "clang/AST/Expr.h"
Anders Carlsson
committed
#include "clang/AST/TargetBuiltins.h"
#include "llvm/Constants.h"
Chris Lattner
committed
#include "llvm/Function.h"
using namespace clang;
using namespace CodeGen;
RValue CodeGenFunction::EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E) {
switch (BuiltinID) {
Chris Lattner
committed
if (getContext().BuiltinInfo.isLibFunction(BuiltinID))
return EmitCallExpr(CGM.getBuiltinLibFunction(BuiltinID),
E->getCallee()->getType(), E->arg_begin(),
E->getNumArgs());
// See if we have a target specific intrinsic.
const char *TargetPrefix = Target.getTargetPrefix();
const char *BuiltinName = getContext().BuiltinInfo.GetName(BuiltinID);
#define GET_LLVM_INTRINSIC_FOR_GCC_BUILTIN
#include "llvm/Intrinsics.gen"
#undef GET_LLVM_INTRINSIC_FOR_GCC_BUILTIN
if (IntrinsicID != Intrinsic::not_intrinsic) {
Function *F = CGM.getIntrinsic(IntrinsicID);
const llvm::FunctionType *FTy = F->getFunctionType();
for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
// 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);
}
Args.push_back(ArgValue);
}
Value *V = Builder.CreateCall(F, &Args[0], &Args[0] + Args.size());
QualType BuiltinRetType = E->getType();
const llvm::Type *RetTy = llvm::Type::VoidTy;
if (!BuiltinRetType->isVoidType()) RetTy = ConvertType(BuiltinRetType);
if (RetTy != V->getType()) {
assert(V->getType()->canLosslesslyBitCastTo(RetTy) &&
"Must be able to losslessly bit cast result type");
V = Builder.CreateBitCast(V, RetTy);
}
return RValue::get(V);
}
Anders Carlsson
committed
// See if we have a target specific builtin that needs to be lowered.
Anders Carlsson
committed
if (strcmp(TargetPrefix, "x86") == 0)
V = EmitX86BuiltinExpr(BuiltinID, E);
else if (strcmp(TargetPrefix, "ppc") == 0)
V = EmitPPCBuiltinExpr(BuiltinID, E);
if (V)
return RValue::get(V);
Chris Lattner
committed
WarnUnsupported(E, "builtin function");
// Unknown builtin, for now just dump it out and return undef.
if (hasAggregateLLVMType(E->getType()))
return RValue::getAggregate(CreateTempAlloca(ConvertType(E->getType())));
return RValue::get(UndefValue::get(ConvertType(E->getType())));
case Builtin::BI__builtin___CFStringMakeConstantString: {
const Expr *Arg = E->getArg(0);
Anders Carlsson
committed
while (1) {
if (const ParenExpr *PE = dyn_cast<ParenExpr>(Arg))
Arg = PE->getSubExpr();
else if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(Arg))
Arg = CE->getSubExpr();
else
break;
}
const StringLiteral *Literal = cast<StringLiteral>(Arg);
std::string S(Literal->getStrData(), Literal->getByteLength());
return RValue::get(CGM.GetAddrOfConstantCFString(S));
}
case Builtin::BI__builtin_va_start:
case Builtin::BI__builtin_va_end: {
const llvm::Type *DestType =
llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
if (ArgValue->getType() != DestType)
ArgValue = Builder.CreateBitCast(ArgValue, DestType,
ArgValue->getNameStart());
Intrinsic::ID inst = (BuiltinID == Builtin::BI__builtin_va_start) ?
Intrinsic::vastart : Intrinsic::vaend;
return RValue::get(Builder.CreateCall(CGM.getIntrinsic(inst), ArgValue));
case Builtin::BI__builtin_classify_type: {
if (!E->isBuiltinClassifyType(Result))
assert(0 && "Expr not __builtin_classify_type!");
Anders Carlsson
committed
case Builtin::BI__builtin_constant_p: {
Anders Carlsson
committed
// FIXME: Analyze the parameter and check if it is a constant.
Result = 0;
Anders Carlsson
committed
}
llvm::BinaryOperator *NegOp =
Builder.CreateNeg(ArgValue, (ArgValue->getName() + "neg").c_str());
Builder.CreateICmpSGE(ArgValue, NegOp->getOperand(0), "abscond");
Builder.CreateSelect(CmpResult, ArgValue, NegOp, "abs");
return RValue::get(Result);
}
case Builtin::BI__builtin_expect:
return RValue::get(EmitScalarExpr(E->getArg(0)));
case Builtin::BI__builtin_bswap32:
case Builtin::BI__builtin_bswap64: {
const llvm::Type *ArgType = ArgValue->getType();
Value *F = CGM.getIntrinsic(Intrinsic::bswap, &ArgType, 1);
return RValue::get(Builder.CreateCall(F, ArgValue, "tmp"));
case Builtin::BI__builtin_inff: {
APFloat f(APFloat::IEEEsingle, APFloat::fcInfinity, false);
return RValue::get(ConstantFP::get(llvm::Type::FloatTy, f));
case Builtin::BI__builtin_huge_val:
case Builtin::BI__builtin_inf:
// FIXME: mapping long double onto double.
case Builtin::BI__builtin_infl: {
APFloat f(APFloat::IEEEdouble, APFloat::fcInfinity, false);
return RValue::get(ConstantFP::get(llvm::Type::DoubleTy, f));
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
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.
Value *LHS = EmitScalarExpr(E->getArg(0));
Value *RHS = EmitScalarExpr(E->getArg(1));
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;
case Builtin::BI__builtin_isunordered:
LHS = Builder.CreateFCmpUNO(LHS, RHS, "cmp");
break;
}
// ZExt bool to int type.
return RValue::get(Builder.CreateZExt(LHS, ConvertType(E->getType()),
"tmp"));
}
case Builtin::BI__builtin_alloca:
return RValue::get(Builder.CreateAlloca(llvm::Type::Int8Ty,
EmitScalarExpr(E->getArg(0)),
"tmp"));
}
return RValue::get(0);
}
Anders Carlsson
committed
Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
llvm::SmallVector<Value*, 4> Ops;
for (unsigned i = 0, e = E->getNumArgs(); i != e; i++)
Ops.push_back(EmitScalarExpr(E->getArg(i)));
Anders Carlsson
committed
switch (BuiltinID) {
default: return 0;
case X86::BI__builtin_ia32_mulps:
return Builder.CreateMul(Ops[0], Ops[1], "mulps");
case X86::BI__builtin_ia32_pand:
return Builder.CreateAnd(Ops[0], Ops[1], "pand");
case X86::BI__builtin_ia32_por:
return Builder.CreateAnd(Ops[0], Ops[1], "por");
case X86::BI__builtin_ia32_pxor:
return Builder.CreateAnd(Ops[0], Ops[1], "pxor");
case X86::BI__builtin_ia32_pandn: {
Ops[0] = Builder.CreateNot(Ops[0], "tmp");
return Builder.CreateAnd(Ops[0], Ops[1], "pandn");
case X86::BI__builtin_ia32_paddb:
case X86::BI__builtin_ia32_paddd:
case X86::BI__builtin_ia32_paddq:
case X86::BI__builtin_ia32_paddw:
case X86::BI__builtin_ia32_addps:
return Builder.CreateAdd(Ops[0], Ops[1], "add");
case X86::BI__builtin_ia32_psubb:
case X86::BI__builtin_ia32_psubd:
case X86::BI__builtin_ia32_psubq:
case X86::BI__builtin_ia32_psubw:
case X86::BI__builtin_ia32_subps:
return Builder.CreateSub(Ops[0], Ops[1], "sub");
case X86::BI__builtin_ia32_divps:
return Builder.CreateFDiv(Ops[0], Ops[1], "divps");
return Builder.CreateMul(Ops[0], Ops[1], "pmul");
return EmitShuffleVector(Ops[0], Ops[1], 4, 12, 5, 13, 6, 14, 7, 15,
"punpckhbw");
case X86::BI__builtin_ia32_punpckhwd:
return EmitShuffleVector(Ops[0], Ops[1], 2, 6, 3, 7, "punpckhwd");
return EmitShuffleVector(Ops[0], Ops[1], 1, 3, "punpckhdq");
return EmitShuffleVector(Ops[0], Ops[1], 0, 8, 1, 9, 2, 10, 3, 11,
"punpcklbw");
case X86::BI__builtin_ia32_punpcklwd:
return EmitShuffleVector(Ops[0], Ops[1], 0, 4, 1, 5, "punpcklwd");
return EmitShuffleVector(Ops[0], Ops[1], 0, 2, "punpckldq");
case X86::BI__builtin_ia32_pslldi:
case X86::BI__builtin_ia32_psllqi:
case X86::BI__builtin_ia32_psllwi:
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: {
Ops[1] = Builder.CreateZExt(Ops[1], llvm::Type::Int64Ty, "zext");
const llvm::Type *Ty = llvm::VectorType::get(llvm::Type::Int64Ty, 1);
Ops[1] = Builder.CreateBitCast(Ops[1], Ty, "bitcast");
const char *name = 0;
Intrinsic::ID ID = Intrinsic::not_intrinsic;
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
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;
}
llvm::Function *F = CGM.getIntrinsic(ID);
return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name);
}
case X86::BI__builtin_ia32_pshufd: {
unsigned i = cast<ConstantInt>(Ops[1])->getZExtValue();
return EmitShuffleVector(Ops[0], Ops[0],
i & 0x3, (i & 0xc) >> 2,
(i & 0x30) >> 4, (i & 0xc0) >> 6,
"pshufd");
}
case X86::BI__builtin_ia32_vec_init_v4hi:
case X86::BI__builtin_ia32_vec_init_v8qi:
case X86::BI__builtin_ia32_vec_init_v2si:
return EmitVector(&Ops[0], Ops.size());
case X86::BI__builtin_ia32_vec_ext_v2si:
return Builder.CreateExtractElement(Ops[0], Ops[1], "result");
case X86::BI__builtin_ia32_cmpordss:
case X86::BI__builtin_ia32_cmpunordss:
case X86::BI__builtin_ia32_cmpeqss:
case X86::BI__builtin_ia32_cmpltss:
case X86::BI__builtin_ia32_cmpless:
case X86::BI__builtin_ia32_cmpneqss:
case X86::BI__builtin_ia32_cmpnltss:
case X86::BI__builtin_ia32_cmpnless: {
unsigned i = 0;
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
const char *name = 0;
switch (BuiltinID) {
default: assert(0 && "Unknown compare builtin!");
case X86::BI__builtin_ia32_cmpeqss:
i = 0;
name = "cmpeqss";
break;
case X86::BI__builtin_ia32_cmpltss:
i = 1;
name = "cmpltss";
break;
case X86::BI__builtin_ia32_cmpless:
i = 2;
name = "cmpless";
break;
case X86::BI__builtin_ia32_cmpunordss:
i = 3;
name = "cmpunordss";
break;
case X86::BI__builtin_ia32_cmpneqss:
i = 4;
name = "cmpneqss";
break;
case X86::BI__builtin_ia32_cmpnltss:
i = 5;
name = "cmpntlss";
break;
case X86::BI__builtin_ia32_cmpnless:
i = 6;
name = "cmpnless";
break;
case X86::BI__builtin_ia32_cmpordss:
i = 7;
name = "cmpordss";
break;
}
Ops.push_back(llvm::ConstantInt::get(llvm::Type::Int8Ty, i));
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse_cmp_ss);
return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name);
}
case X86::BI__builtin_ia32_cmpordps:
case X86::BI__builtin_ia32_cmpunordps:
case X86::BI__builtin_ia32_cmpeqps:
case X86::BI__builtin_ia32_cmpltps:
case X86::BI__builtin_ia32_cmpleps:
case X86::BI__builtin_ia32_cmpneqps:
case X86::BI__builtin_ia32_cmpngtps:
case X86::BI__builtin_ia32_cmpnltps:
case X86::BI__builtin_ia32_cmpgtps:
case X86::BI__builtin_ia32_cmpgeps:
case X86::BI__builtin_ia32_cmpngeps:
case X86::BI__builtin_ia32_cmpnleps: {
unsigned i = 0;
const char *name = 0;
bool ShouldSwap = false;
switch (BuiltinID) {
default: assert(0 && "Unknown compare builtin!");
case X86::BI__builtin_ia32_cmpeqps: i = 0; name = "cmpeqps"; break;
case X86::BI__builtin_ia32_cmpltps: i = 1; name = "cmpltps"; break;
case X86::BI__builtin_ia32_cmpleps: i = 2; name = "cmpleps"; break;
case X86::BI__builtin_ia32_cmpunordps: i = 3; name = "cmpunordps"; break;
case X86::BI__builtin_ia32_cmpneqps: i = 4; name = "cmpneqps"; break;
case X86::BI__builtin_ia32_cmpnltps: i = 5; name = "cmpntlps"; break;
case X86::BI__builtin_ia32_cmpnleps: i = 6; name = "cmpnleps"; break;
case X86::BI__builtin_ia32_cmpordps: i = 7; name = "cmpordps"; break;
ShouldSwap = true;
i = 1;
name = "cmpgtps";
break;
case X86::BI__builtin_ia32_cmpgeps:
i = 2;
name = "cmpgeps";
ShouldSwap = true;
break;
case X86::BI__builtin_ia32_cmpngtps:
i = 5;
name = "cmpngtps";
ShouldSwap = true;
break;
case X86::BI__builtin_ia32_cmpngeps:
i = 6;
name = "cmpngeps";
ShouldSwap = true;
break;
}
if (ShouldSwap)
std::swap(Ops[0], Ops[1]);
Ops.push_back(llvm::ConstantInt::get(llvm::Type::Int8Ty, i));
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse_cmp_ps);
return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name);
}
case X86::BI__builtin_ia32_movss:
return EmitShuffleVector(Ops[0], Ops[1], 4, 1, 2, 3, "movss");
case X86::BI__builtin_ia32_shufps:
unsigned i = cast<ConstantInt>(Ops[2])->getZExtValue();
return EmitShuffleVector(Ops[0], Ops[1],
i & 0x3, (i & 0xc) >> 2,
((i & 0x30) >> 4) + 4,
((i & 0x60) >> 6) + 4, "shufps");
Anders Carlsson
committed
}
}
Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
Anders Carlsson
committed
switch (BuiltinID) {