blob: abb419ce3401cfe1a3da95e9991a6127a3708911 [file] [log] [blame]
/* LLVM LOCAL begin (ENTIRE FILE!) */
/* High-level LLVM backend interface
Copyright (C) 2005 Free Software Foundation, Inc.
Contributed by Evan Cheng (evan.cheng@apple.com)
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
//===----------------------------------------------------------------------===//
// This is a C++ source file that implements specific llvm IA-32 ABI.
//===----------------------------------------------------------------------===//
#include "llvm-abi.h"
#include "llvm-internal.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/Intrinsics.h"
#include "llvm/Module.h"
#include "llvm-i386-target.h"
extern "C" {
#include "toplev.h"
}
/* TargetIntrinsicLower - For builtins that we want to expand to normal LLVM
* code, emit the code now. If we can handle the code, this macro should emit
* the code, return true.
*/
bool TreeToLLVM::TargetIntrinsicLower(tree exp,
unsigned FnCode,
const MemRef *DestLoc,
Value *&Result,
const Type *ResultType,
std::vector<Value*> &Ops) {
switch (FnCode) {
default: break;
case IX86_BUILTIN_ADDPS:
case IX86_BUILTIN_ADDPD:
case IX86_BUILTIN_PADDB:
case IX86_BUILTIN_PADDW:
case IX86_BUILTIN_PADDD:
case IX86_BUILTIN_PADDQ:
case IX86_BUILTIN_PADDB128:
case IX86_BUILTIN_PADDW128:
case IX86_BUILTIN_PADDD128:
case IX86_BUILTIN_PADDQ128:
Result = Builder.CreateAdd(Ops[0], Ops[1], "tmp");
return true;
case IX86_BUILTIN_SUBPS:
case IX86_BUILTIN_SUBPD:
case IX86_BUILTIN_PSUBB:
case IX86_BUILTIN_PSUBW:
case IX86_BUILTIN_PSUBD:
case IX86_BUILTIN_PSUBQ:
case IX86_BUILTIN_PSUBB128:
case IX86_BUILTIN_PSUBW128:
case IX86_BUILTIN_PSUBD128:
case IX86_BUILTIN_PSUBQ128:
Result = Builder.CreateSub(Ops[0], Ops[1], "tmp");
return true;
case IX86_BUILTIN_MULPS:
case IX86_BUILTIN_MULPD:
case IX86_BUILTIN_PMULLW:
case IX86_BUILTIN_PMULLW128:
Result = Builder.CreateMul(Ops[0], Ops[1], "tmp");
return true;
case IX86_BUILTIN_PSLLWI: {
Function *psllw =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_mmx_psll_w);
Ops[1] = Builder.CreateZExt(Ops[1], Type::Int64Ty, "zext");
Ops[1] = BuildVector(Ops[1], NULL);
Result = Builder.CreateCall(psllw, Ops.begin(), Ops.begin()+2, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_PSLLWI128: {
Function *psllw =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_sse2_psll_w);
Value *Undef = UndefValue::get(Type::Int32Ty);
Ops[1] = BuildVector(Ops[1], Undef, Undef, Undef, NULL);
Ops[1] = Builder.CreateBitCast(Ops[1], Ops[0]->getType(), "tmp");
Result = Builder.CreateCall(psllw, Ops.begin(), Ops.begin()+2, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_PSLLDI: {
Function *pslld =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_mmx_psll_d);
Ops[1] = Builder.CreateZExt(Ops[1], Type::Int64Ty, "zext");
Ops[1] = BuildVector(Ops[1], NULL);
Result = Builder.CreateCall(pslld, Ops.begin(), Ops.begin()+2, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_PSLLDI128: {
Function *pslld
= Intrinsic::getDeclaration(TheModule, Intrinsic::x86_sse2_psll_d);
Value *Undef = UndefValue::get(Type::Int32Ty);
Ops[1] = BuildVector(Ops[1], Undef, Undef, Undef, NULL);
Result = Builder.CreateCall(pslld, Ops.begin(), Ops.begin()+2, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_PSLLQI: {
Function *psllq =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_mmx_psll_q);
Ops[1] = Builder.CreateZExt(Ops[1], Type::Int64Ty, "zext");
Ops[1] = BuildVector(Ops[1], NULL);
Result = Builder.CreateCall(psllq, Ops.begin(), Ops.begin()+2, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_PSLLQI128: {
Function *psllq =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_sse2_psll_q);
Value *Undef = UndefValue::get(Type::Int32Ty);
Ops[1] = BuildVector(Ops[1], Undef, Undef, Undef, NULL);
Ops[1] = Builder.CreateBitCast(Ops[1], Ops[0]->getType(), "tmp");
Result = Builder.CreateCall(psllq, Ops.begin(), Ops.begin()+2, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_PSRLWI: {
Function *psrlw =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_mmx_psrl_w);
Ops[1] = Builder.CreateZExt(Ops[1], Type::Int64Ty, "zext");
Ops[1] = BuildVector(Ops[1], NULL);
Result = Builder.CreateCall(psrlw, Ops.begin(), Ops.begin()+2, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_PSRLWI128: {
Function *psrlw =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_sse2_psrl_w);
Value *Undef = UndefValue::get(Type::Int32Ty);
Ops[1] = BuildVector(Ops[1], Undef, Undef, Undef, NULL);
Ops[1] = Builder.CreateBitCast(Ops[1], Ops[0]->getType(), "tmp");
Result = Builder.CreateCall(psrlw, Ops.begin(), Ops.begin()+2, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_PSRLDI: {
Function *psrld =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_mmx_psrl_d);
Ops[1] = Builder.CreateZExt(Ops[1], Type::Int64Ty, "zext");
Ops[1] = BuildVector(Ops[1], NULL);
Result = Builder.CreateCall(psrld, Ops.begin(), Ops.begin()+2, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_PSRLDI128: {
Function *psrld =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_sse2_psrl_d);
Value *Undef = UndefValue::get(Type::Int32Ty);
Ops[1] = BuildVector(Ops[1], Undef, Undef, Undef, NULL);
Result = Builder.CreateCall(psrld, Ops.begin(), Ops.begin()+2, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_PSRLQI: {
Function *psrlq =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_mmx_psrl_q);
Ops[1] = Builder.CreateZExt(Ops[1], Type::Int64Ty, "zext");
Ops[1] = BuildVector(Ops[1], NULL);
Result = Builder.CreateCall(psrlq, Ops.begin(), Ops.begin()+2, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_PSRLQI128: {
Function *psrlq =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_sse2_psrl_q);
Value *Undef = UndefValue::get(Type::Int32Ty);
Ops[1] = BuildVector(Ops[1], Undef, Undef, Undef, NULL);
Ops[1] = Builder.CreateBitCast(Ops[1], Ops[0]->getType(), "tmp");
Result = Builder.CreateCall(psrlq, Ops.begin(), Ops.begin()+2, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_PSRAWI: {
Function *psraw =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_mmx_psra_w);
Ops[1] = Builder.CreateZExt(Ops[1], Type::Int64Ty, "zext");
Ops[1] = BuildVector(Ops[1], NULL);
Result = Builder.CreateCall(psraw, Ops.begin(), Ops.begin()+2, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_PSRAWI128: {
Function *psraw =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_sse2_psra_w);
Value *Undef = UndefValue::get(Type::Int32Ty);
Ops[1] = BuildVector(Ops[1], Undef, Undef, Undef, NULL);
Ops[1] = Builder.CreateBitCast(Ops[1], Ops[0]->getType(), "tmp");
Result = Builder.CreateCall(psraw, Ops.begin(), Ops.begin()+2, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_PSRADI: {
Function *psrad =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_mmx_psra_d);
Ops[1] = Builder.CreateZExt(Ops[1], Type::Int64Ty, "zext");
Ops[1] = BuildVector(Ops[1], NULL);
Result = Builder.CreateCall(psrad, Ops.begin(), Ops.begin()+2, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_PSRADI128: {
Function *psrad =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_sse2_psra_d);
Value *Undef = UndefValue::get(Type::Int32Ty);
Ops[1] = BuildVector(Ops[1], Undef, Undef, Undef, NULL);
Result = Builder.CreateCall(psrad, Ops.begin(), Ops.begin()+2, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_DIVPS:
case IX86_BUILTIN_DIVPD:
Result = Builder.CreateFDiv(Ops[0], Ops[1], "tmp");
return true;
case IX86_BUILTIN_PAND:
case IX86_BUILTIN_PAND128:
Result = Builder.CreateAnd(Ops[0], Ops[1], "tmp");
return true;
case IX86_BUILTIN_PANDN:
case IX86_BUILTIN_PANDN128:
Ops[0] = Builder.CreateNot(Ops[0], "tmp");
Result = Builder.CreateAnd(Ops[0], Ops[1], "tmp");
return true;
case IX86_BUILTIN_POR:
case IX86_BUILTIN_POR128:
Result = Builder.CreateOr(Ops[0], Ops[1], "tmp");
return true;
case IX86_BUILTIN_PXOR:
case IX86_BUILTIN_PXOR128:
Result = Builder.CreateXor(Ops[0], Ops[1], "tmp");
return true;
case IX86_BUILTIN_ANDPS:
case IX86_BUILTIN_ORPS:
case IX86_BUILTIN_XORPS:
case IX86_BUILTIN_ANDNPS:
case IX86_BUILTIN_ANDPD:
case IX86_BUILTIN_ORPD:
case IX86_BUILTIN_XORPD:
case IX86_BUILTIN_ANDNPD:
if (cast<VectorType>(ResultType)->getNumElements() == 4) // v4f32
Ops[0] = Builder.CreateBitCast(Ops[0], VectorType::get(Type::Int32Ty, 4),
"tmp");
else // v2f64
Ops[0] = Builder.CreateBitCast(Ops[0], VectorType::get(Type::Int64Ty, 2),
"tmp");
Ops[1] = Builder.CreateBitCast(Ops[1], Ops[0]->getType(), "tmp");
switch (FnCode) {
case IX86_BUILTIN_ANDPS:
case IX86_BUILTIN_ANDPD:
Result = Builder.CreateAnd(Ops[0], Ops[1], "tmp");
break;
case IX86_BUILTIN_ORPS:
case IX86_BUILTIN_ORPD:
Result = Builder.CreateOr (Ops[0], Ops[1], "tmp");
break;
case IX86_BUILTIN_XORPS:
case IX86_BUILTIN_XORPD:
Result = Builder.CreateXor(Ops[0], Ops[1], "tmp");
break;
case IX86_BUILTIN_ANDNPS:
case IX86_BUILTIN_ANDNPD:
Ops[0] = Builder.CreateNot(Ops[0], "tmp");
Result = Builder.CreateAnd(Ops[0], Ops[1], "tmp");
break;
}
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
case IX86_BUILTIN_SHUFPS:
if (ConstantInt *Elt = dyn_cast<ConstantInt>(Ops[2])) {
int EV = Elt->getZExtValue();
Result = BuildVectorShuffle(Ops[0], Ops[1],
((EV & 0x03) >> 0), ((EV & 0x0c) >> 2),
((EV & 0x30) >> 4)+4, ((EV & 0xc0) >> 6)+4);
} else {
error("%Hmask must be an immediate", &EXPR_LOCATION(exp));
Result = Ops[0];
}
return true;
case IX86_BUILTIN_PSHUFW:
case IX86_BUILTIN_PSHUFD:
if (ConstantInt *Elt = dyn_cast<ConstantInt>(Ops[1])) {
int EV = Elt->getZExtValue();
Result = BuildVectorShuffle(Ops[0], Ops[0],
((EV & 0x03) >> 0), ((EV & 0x0c) >> 2),
((EV & 0x30) >> 4), ((EV & 0xc0) >> 6));
} else {
error("%Hmask must be an immediate", &EXPR_LOCATION(exp));
Result = Ops[0];
}
return true;
case IX86_BUILTIN_PSHUFHW:
if (ConstantInt *Elt = dyn_cast<ConstantInt>(Ops[1])) {
int EV = Elt->getZExtValue();
Result = BuildVectorShuffle(Ops[0], Ops[0],
0, 1, 2, 3,
((EV & 0x03) >> 0)+4, ((EV & 0x0c) >> 2)+4,
((EV & 0x30) >> 4)+4, ((EV & 0xc0) >> 6)+4);
return true;
}
return false;
case IX86_BUILTIN_PSHUFLW:
if (ConstantInt *Elt = dyn_cast<ConstantInt>(Ops[1])) {
int EV = Elt->getZExtValue();
Result = BuildVectorShuffle(Ops[0], Ops[0],
((EV & 0x03) >> 0), ((EV & 0x0c) >> 2),
((EV & 0x30) >> 4), ((EV & 0xc0) >> 6),
4, 5, 6, 7);
} else {
error("%Hmask must be an immediate", &EXPR_LOCATION(exp));
Result = Ops[0];
}
return true;
case IX86_BUILTIN_PUNPCKHBW:
Result = BuildVectorShuffle(Ops[0], Ops[1], 4, 12, 5, 13,
6, 14, 7, 15);
return true;
case IX86_BUILTIN_PUNPCKHWD:
Result = BuildVectorShuffle(Ops[0], Ops[1], 2, 6, 3, 7);
return true;
case IX86_BUILTIN_PUNPCKHDQ:
Result = BuildVectorShuffle(Ops[0], Ops[1], 1, 3);
return true;
case IX86_BUILTIN_PUNPCKLBW:
Result = BuildVectorShuffle(Ops[0], Ops[1], 0, 8, 1, 9,
2, 10, 3, 11);
return true;
case IX86_BUILTIN_PUNPCKLWD:
Result = BuildVectorShuffle(Ops[0], Ops[1], 0, 4, 1, 5);
return true;
case IX86_BUILTIN_PUNPCKLDQ:
Result = BuildVectorShuffle(Ops[0], Ops[1], 0, 2);
return true;
case IX86_BUILTIN_PUNPCKHBW128:
Result = BuildVectorShuffle(Ops[0], Ops[1], 8, 24, 9, 25,
10, 26, 11, 27,
12, 28, 13, 29,
14, 30, 15, 31);
return true;
case IX86_BUILTIN_PUNPCKHWD128:
Result = BuildVectorShuffle(Ops[0], Ops[1], 4, 12, 5, 13, 6, 14, 7, 15);
return true;
case IX86_BUILTIN_PUNPCKHDQ128:
Result = BuildVectorShuffle(Ops[0], Ops[1], 2, 6, 3, 7);
return true;
case IX86_BUILTIN_PUNPCKLBW128:
Result = BuildVectorShuffle(Ops[0], Ops[1], 0, 16, 1, 17,
2, 18, 3, 19,
4, 20, 5, 21,
6, 22, 7, 23);
return true;
case IX86_BUILTIN_PUNPCKLWD128:
Result = BuildVectorShuffle(Ops[0], Ops[1], 0, 8, 1, 9, 2, 10, 3, 11);
return true;
case IX86_BUILTIN_PUNPCKLDQ128:
Result = BuildVectorShuffle(Ops[0], Ops[1], 0, 4, 1, 5);
return true;
case IX86_BUILTIN_UNPCKHPS:
Result = BuildVectorShuffle(Ops[0], Ops[1], 2, 6, 3, 7);
return true;
case IX86_BUILTIN_UNPCKLPS:
Result = BuildVectorShuffle(Ops[0], Ops[1], 0, 4, 1, 5);
return true;
case IX86_BUILTIN_MOVHLPS:
Result = BuildVectorShuffle(Ops[0], Ops[1], 6, 7, 2, 3);
return true;
case IX86_BUILTIN_MOVLHPS:
Result = BuildVectorShuffle(Ops[0], Ops[1], 0, 1, 4, 5);
return true;
case IX86_BUILTIN_MOVSS:
Result = BuildVectorShuffle(Ops[0], Ops[1], 4, 1, 2, 3);
return true;
case IX86_BUILTIN_MOVQ: {
Value *Zero = ConstantInt::get(Type::Int32Ty, 0);
Result = BuildVector(Zero, Zero, Zero, Zero, NULL);
Result = BuildVectorShuffle(Result, Ops[0], 4, 5, 2, 3);
return true;
}
case IX86_BUILTIN_LOADQ: {
PointerType *f64Ptr = PointerType::getUnqual(Type::DoubleTy);
Value *Zero = ConstantFP::get(Type::DoubleTy, APFloat(0.0));
Ops[0] = Builder.CreateBitCast(Ops[0], f64Ptr, "tmp");
Ops[0] = Builder.CreateLoad(Ops[0], "tmp");
Result = BuildVector(Ops[0], Zero, NULL);
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_LOADHPS: {
PointerType *f64Ptr = PointerType::getUnqual(Type::DoubleTy);
Ops[1] = Builder.CreateBitCast(Ops[1], f64Ptr, "tmp");
Value *Load = Builder.CreateLoad(Ops[1], "tmp");
Ops[1] = BuildVector(Load, UndefValue::get(Type::DoubleTy), NULL);
Ops[1] = Builder.CreateBitCast(Ops[1], ResultType, "tmp");
Result = BuildVectorShuffle(Ops[0], Ops[1], 0, 1, 4, 5);
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_LOADLPS: {
PointerType *f64Ptr = PointerType::getUnqual(Type::DoubleTy);
Ops[1] = Builder.CreateBitCast(Ops[1], f64Ptr, "tmp");
Value *Load = Builder.CreateLoad(Ops[1], "tmp");
Ops[1] = BuildVector(Load, UndefValue::get(Type::DoubleTy), NULL);
Ops[1] = Builder.CreateBitCast(Ops[1], ResultType, "tmp");
Result = BuildVectorShuffle(Ops[0], Ops[1], 4, 5, 2, 3);
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_STOREHPS: {
VectorType *v2f64 = VectorType::get(Type::DoubleTy, 2);
PointerType *f64Ptr = PointerType::getUnqual(Type::DoubleTy);
Ops[0] = Builder.CreateBitCast(Ops[0], f64Ptr, "tmp");
Value *Idx = ConstantInt::get(Type::Int32Ty, 1);
Ops[1] = Builder.CreateBitCast(Ops[1], v2f64, "tmp");
Ops[1] = Builder.CreateExtractElement(Ops[1], Idx, "tmp");
Result = Builder.CreateStore(Ops[1], Ops[0]);
return true;
}
case IX86_BUILTIN_STORELPS: {
VectorType *v2f64 = VectorType::get(Type::DoubleTy, 2);
PointerType *f64Ptr = PointerType::getUnqual(Type::DoubleTy);
Ops[0] = Builder.CreateBitCast(Ops[0], f64Ptr, "tmp");
Value *Idx = ConstantInt::get(Type::Int32Ty, 0);
Ops[1] = Builder.CreateBitCast(Ops[1], v2f64, "tmp");
Ops[1] = Builder.CreateExtractElement(Ops[1], Idx, "tmp");
Result = Builder.CreateStore(Ops[1], Ops[0]);
return true;
}
case IX86_BUILTIN_MOVSHDUP:
Result = BuildVectorShuffle(Ops[0], Ops[0], 1, 1, 3, 3);
return true;
case IX86_BUILTIN_MOVSLDUP:
Result = BuildVectorShuffle(Ops[0], Ops[0], 0, 0, 2, 2);
return true;
case IX86_BUILTIN_VEC_INIT_V2SI:
Result = BuildVector(Ops[0], Ops[1], NULL);
return true;
case IX86_BUILTIN_VEC_INIT_V4HI:
// Sometimes G++ promotes arguments to int.
for (unsigned i = 0; i != 4; ++i)
Ops[i] = Builder.CreateIntCast(Ops[i], Type::Int16Ty, false, "tmp");
Result = BuildVector(Ops[0], Ops[1], Ops[2], Ops[3], NULL);
return true;
case IX86_BUILTIN_VEC_INIT_V8QI:
// Sometimes G++ promotes arguments to int.
for (unsigned i = 0; i != 8; ++i)
Ops[i] = Builder.CreateIntCast(Ops[i], Type::Int8Ty, false, "tmp");
Result = BuildVector(Ops[0], Ops[1], Ops[2], Ops[3],
Ops[4], Ops[5], Ops[6], Ops[7], NULL);
return true;
case IX86_BUILTIN_VEC_EXT_V2SI:
case IX86_BUILTIN_VEC_EXT_V4HI:
case IX86_BUILTIN_VEC_EXT_V2DF:
case IX86_BUILTIN_VEC_EXT_V2DI:
case IX86_BUILTIN_VEC_EXT_V4SI:
case IX86_BUILTIN_VEC_EXT_V4SF:
case IX86_BUILTIN_VEC_EXT_V8HI:
Result = Builder.CreateExtractElement(Ops[0], Ops[1], "tmp");
return true;
case IX86_BUILTIN_VEC_SET_V4HI:
case IX86_BUILTIN_VEC_SET_V8HI:
// GCC sometimes doesn't produce the right element type.
Ops[1] = Builder.CreateIntCast(Ops[1], Type::Int16Ty, false, "tmp");
Result = Builder.CreateInsertElement(Ops[0], Ops[1], Ops[2], "tmp");
return true;
case IX86_BUILTIN_CMPEQPS:
case IX86_BUILTIN_CMPLTPS:
case IX86_BUILTIN_CMPLEPS:
case IX86_BUILTIN_CMPGTPS:
case IX86_BUILTIN_CMPGEPS:
case IX86_BUILTIN_CMPNEQPS:
case IX86_BUILTIN_CMPNLTPS:
case IX86_BUILTIN_CMPNLEPS:
case IX86_BUILTIN_CMPNGTPS:
case IX86_BUILTIN_CMPNGEPS:
case IX86_BUILTIN_CMPORDPS:
case IX86_BUILTIN_CMPUNORDPS: {
Function *cmpps =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_sse_cmp_ps);
bool flip = false;
unsigned PredCode;
switch (FnCode) {
default: assert(0 && "Unknown fncode!");
case IX86_BUILTIN_CMPEQPS: PredCode = 0; break;
case IX86_BUILTIN_CMPLTPS: PredCode = 1; break;
case IX86_BUILTIN_CMPGTPS: PredCode = 1; flip = true; break;
case IX86_BUILTIN_CMPLEPS: PredCode = 2; break;
case IX86_BUILTIN_CMPGEPS: PredCode = 2; flip = true; break;
case IX86_BUILTIN_CMPUNORDPS: PredCode = 3; break;
case IX86_BUILTIN_CMPNEQPS: PredCode = 4; break;
case IX86_BUILTIN_CMPNLTPS: PredCode = 5; break;
case IX86_BUILTIN_CMPNGTPS: PredCode = 5; flip = true; break;
case IX86_BUILTIN_CMPNLEPS: PredCode = 6; break;
case IX86_BUILTIN_CMPNGEPS: PredCode = 6; flip = true; break;
case IX86_BUILTIN_CMPORDPS: PredCode = 7; break;
}
Value *Pred = ConstantInt::get(Type::Int8Ty, PredCode);
Value *Arg0 = Ops[0];
Value *Arg1 = Ops[1];
if (flip) std::swap(Arg0, Arg1);
Value *CallOps[3] = { Arg0, Arg1, Pred };
Result = Builder.CreateCall(cmpps, CallOps, CallOps+3, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_CMPEQSS:
case IX86_BUILTIN_CMPLTSS:
case IX86_BUILTIN_CMPLESS:
case IX86_BUILTIN_CMPNEQSS:
case IX86_BUILTIN_CMPNLTSS:
case IX86_BUILTIN_CMPNLESS:
case IX86_BUILTIN_CMPNGTSS:
case IX86_BUILTIN_CMPNGESS:
case IX86_BUILTIN_CMPORDSS:
case IX86_BUILTIN_CMPUNORDSS: {
Function *cmpss =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_sse_cmp_ss);
unsigned PredCode;
switch (FnCode) {
default: assert(0 && "Unknown fncode");
case IX86_BUILTIN_CMPEQSS: PredCode = 0; break;
case IX86_BUILTIN_CMPLTSS: PredCode = 1; break;
case IX86_BUILTIN_CMPLESS: PredCode = 2; break;
case IX86_BUILTIN_CMPUNORDSS: PredCode = 3; break;
case IX86_BUILTIN_CMPNEQSS: PredCode = 4; break;
case IX86_BUILTIN_CMPNLTSS: PredCode = 5; break;
case IX86_BUILTIN_CMPNLESS: PredCode = 6; break;
case IX86_BUILTIN_CMPORDSS: PredCode = 7; break;
}
Value *Pred = ConstantInt::get(Type::Int8Ty, PredCode);
Value *CallOps[3] = { Ops[0], Ops[1], Pred };
Result = Builder.CreateCall(cmpss, CallOps, CallOps+3, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_CMPEQPD:
case IX86_BUILTIN_CMPLTPD:
case IX86_BUILTIN_CMPLEPD:
case IX86_BUILTIN_CMPGTPD:
case IX86_BUILTIN_CMPGEPD:
case IX86_BUILTIN_CMPNEQPD:
case IX86_BUILTIN_CMPNLTPD:
case IX86_BUILTIN_CMPNLEPD:
case IX86_BUILTIN_CMPNGTPD:
case IX86_BUILTIN_CMPNGEPD:
case IX86_BUILTIN_CMPORDPD:
case IX86_BUILTIN_CMPUNORDPD: {
Function *cmppd =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_sse2_cmp_pd);
bool flip = false;
unsigned PredCode;
switch (FnCode) {
default: assert(0 && "Unknown fncode!");
case IX86_BUILTIN_CMPEQPD: PredCode = 0; break;
case IX86_BUILTIN_CMPLTPD: PredCode = 1; break;
case IX86_BUILTIN_CMPGTPD: PredCode = 1; flip = true; break;
case IX86_BUILTIN_CMPLEPD: PredCode = 2; break;
case IX86_BUILTIN_CMPGEPD: PredCode = 2; flip = true; break;
case IX86_BUILTIN_CMPUNORDPD: PredCode = 3; break;
case IX86_BUILTIN_CMPNEQPD: PredCode = 4; break;
case IX86_BUILTIN_CMPNLTPD: PredCode = 5; break;
case IX86_BUILTIN_CMPNGTPD: PredCode = 5; flip = true; break;
case IX86_BUILTIN_CMPNLEPD: PredCode = 6; break;
case IX86_BUILTIN_CMPNGEPD: PredCode = 6; flip = true; break;
case IX86_BUILTIN_CMPORDPD: PredCode = 7; break;
}
Value *Pred = ConstantInt::get(Type::Int8Ty, PredCode);
Value *Arg0 = Ops[0];
Value *Arg1 = Ops[1];
if (flip) std::swap(Arg0, Arg1);
Value *CallOps[3] = { Arg0, Arg1, Pred };
Result = Builder.CreateCall(cmppd, CallOps, CallOps+3, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_CMPEQSD:
case IX86_BUILTIN_CMPLTSD:
case IX86_BUILTIN_CMPLESD:
case IX86_BUILTIN_CMPNEQSD:
case IX86_BUILTIN_CMPNLTSD:
case IX86_BUILTIN_CMPNLESD:
case IX86_BUILTIN_CMPORDSD:
case IX86_BUILTIN_CMPUNORDSD: {
Function *cmpsd =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_sse2_cmp_sd);
unsigned PredCode;
switch (FnCode) {
default: assert(0 && "Unknown fncode");
case IX86_BUILTIN_CMPEQSD: PredCode = 0; break;
case IX86_BUILTIN_CMPLTSD: PredCode = 1; break;
case IX86_BUILTIN_CMPLESD: PredCode = 2; break;
case IX86_BUILTIN_CMPUNORDSD: PredCode = 3; break;
case IX86_BUILTIN_CMPNEQSD: PredCode = 4; break;
case IX86_BUILTIN_CMPNLTSD: PredCode = 5; break;
case IX86_BUILTIN_CMPNLESD: PredCode = 6; break;
case IX86_BUILTIN_CMPORDSD: PredCode = 7; break;
}
Value *Pred = ConstantInt::get(Type::Int8Ty, PredCode);
Value *CallOps[3] = { Ops[0], Ops[1], Pred };
Result = Builder.CreateCall(cmpsd, CallOps, CallOps+3, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case IX86_BUILTIN_LDMXCSR: {
Function *ldmxcsr =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_sse_ldmxcsr);
Value *Ptr = CreateTemporary(Type::Int32Ty);
Builder.CreateStore(Ops[0], Ptr);
Ptr = Builder.CreateBitCast(Ptr, PointerType::getUnqual(Type::Int8Ty), "tmp");
Result = Builder.CreateCall(ldmxcsr, Ptr);
return true;
}
case IX86_BUILTIN_STMXCSR: {
Function *stmxcsr =
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_sse_stmxcsr);
Value *Ptr = CreateTemporary(Type::Int32Ty);
Value *BPtr = Builder.CreateBitCast(Ptr, PointerType::getUnqual(Type::Int8Ty),
"tmp");
Builder.CreateCall(stmxcsr, BPtr);
Result = Builder.CreateLoad(Ptr, "tmp");
return true;
}
}
return false;
}
/* These are defined in i386.c */
#define MAX_CLASSES 4
extern "C" enum machine_mode ix86_getNaturalModeForType(tree);
extern "C" int ix86_HowToPassArgument(enum machine_mode, tree, int, int*, int*);
extern "C" int ix86_ClassifyArgument(enum machine_mode, tree,
enum x86_64_reg_class classes[MAX_CLASSES], int);
/* Target hook for llvm-abi.h. It returns true if an aggregate of the
specified type should be passed in memory. This is only called for
x86-64. */
static bool llvm_x86_64_should_pass_aggregate_in_memory(tree TreeType,
enum machine_mode Mode){
int IntRegs, SSERegs;
/* If ix86_HowToPassArgument return 0, then it's passed byval in memory.*/
return !ix86_HowToPassArgument(Mode, TreeType, 0, &IntRegs, &SSERegs);
}
/* Returns true if all elements of the type are integer types. */
static bool llvm_x86_is_all_integer_types(const Type *Ty) {
for (Type::subtype_iterator I = Ty->subtype_begin(), E = Ty->subtype_end();
I != E; ++I) {
const Type *STy = I->get();
if (!STy->isIntOrIntVector() && !isa<PointerType>(STy))
return false;
}
return true;
}
/* Target hook for llvm-abi.h. It returns true if an aggregate of the
specified type should be passed in a number of registers of mixed types.
It also returns a vector of types that correspond to the registers used
for parameter passing. This is only called for x86-32. */
bool
llvm_x86_32_should_pass_aggregate_in_mixed_regs(tree TreeType, const Type *Ty,
std::vector<const Type*> &Elts){
// If this is a small fixed size type, investigate it.
HOST_WIDE_INT SrcSize = int_size_in_bytes(TreeType);
if (SrcSize <= 0 || SrcSize > 16)
return false;
// X86-32 passes aggregates on the stack. If this is an extremely simple
// aggregate whose elements would be passed the same if passed as scalars,
// pass them that way in order to promote SROA on the caller and callee side.
// Note that we can't support passing all structs this way. For example,
// {i16, i16} should be passed in on 32-bit unit, which is not how "i16, i16"
// would be passed as stand-alone arguments.
const StructType *STy = dyn_cast<StructType>(Ty);
if (!STy || STy->isPacked()) return false;
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
const Type *EltTy = STy->getElementType(i);
// 32 and 64-bit integers are fine, as are float and double. Long double
// (which can be picked as the type for a union of 16 bytes) is not fine,
// as loads and stores of it get only 10 bytes.
if (EltTy == Type::Int32Ty ||
EltTy == Type::Int64Ty ||
EltTy == Type::FloatTy ||
EltTy == Type::DoubleTy ||
isa<PointerType>(EltTy)) {
Elts.push_back(EltTy);
continue;
}
// TODO: Vectors are also ok to pass if they don't require extra alignment.
// TODO: We can also pass structs like {i8, i32}.
Elts.clear();
return false;
}
return true;
}
/* Target hook for llvm-abi.h. It returns true if an aggregate of the
specified type should be passed in memory. */
bool llvm_x86_should_pass_aggregate_in_memory(tree TreeType, const Type *Ty) {
enum machine_mode Mode = ix86_getNaturalModeForType(TreeType);
HOST_WIDE_INT Bytes =
(Mode == BLKmode) ? int_size_in_bytes(TreeType) : (int) GET_MODE_SIZE(Mode);
// Zero sized array, struct, or class, not passed in memory.
if (Bytes == 0)
return false;
if (TARGET_64BIT &&
(Bytes == GET_MODE_SIZE(SImode) || Bytes == GET_MODE_SIZE(DImode))) {
// 32-bit or 64-bit and all elements are integers, not passed in memory.
const Type *Ty = ConvertType(TreeType);
if (llvm_x86_is_all_integer_types(Ty))
return false;
}
if (!TARGET_64BIT) {
std::vector<const Type*> Elts;
return !llvm_x86_32_should_pass_aggregate_in_mixed_regs(TreeType, Ty, Elts);
}
return llvm_x86_64_should_pass_aggregate_in_memory(TreeType, Mode);
}
/* Target hook for llvm-abi.h. It returns true if an aggregate of the
specified type should be passed in a number of registers of mixed types.
It also returns a vector of types that correspond to the registers used
for parameter passing. This is only called for x86-64. */
bool
llvm_x86_64_should_pass_aggregate_in_mixed_regs(tree TreeType, const Type *Ty,
std::vector<const Type*> &Elts){
enum x86_64_reg_class Class[MAX_CLASSES];
enum machine_mode Mode = ix86_getNaturalModeForType(TreeType);
HOST_WIDE_INT Bytes =
(Mode == BLKmode) ? int_size_in_bytes(TreeType) : (int) GET_MODE_SIZE(Mode);
int NumClasses = ix86_ClassifyArgument(Mode, TreeType, Class, 0);
if (!NumClasses)
return false;
for (int i = 0; i < NumClasses; ++i) {
switch (Class[i]) {
case X86_64_INTEGER_CLASS:
case X86_64_INTEGERSI_CLASS:
Elts.push_back(Type::Int64Ty);
Bytes -= 8;
break;
case X86_64_SSE_CLASS:
// If it's a SSE class argument, then one of the followings are possible:
// 1. 1 x SSE, size is 8: 1 x Double.
// 2. 1 x SSE + 1 x SSEUP, size is 16: 1 x <4 x i32>, <4 x f32>,
// <2 x i64>, or <2 x f64>.
// 3. 1 x SSE + 1 x SSESF, size is 12: 1 x Double, 1 x Float.
// 4. 2 x SSE, size is 16: 2 x Double.
if ((NumClasses-i) == 1) {
if (Bytes == 8) {
Elts.push_back(Type::DoubleTy);
Bytes -= 8;
} else
assert(0 && "Not yet handled!");
} else if ((NumClasses-i) == 2) {
if (Class[i+1] == X86_64_SSEUP_CLASS) {
const Type *Ty = ConvertType(TreeType);
if (const StructType *STy = dyn_cast<StructType>(Ty))
// Look pass the struct wrapper.
if (STy->getNumElements() == 1)
Ty = STy->getElementType(0);
if (const VectorType *VTy = dyn_cast<VectorType>(Ty)) {
if (VTy->getNumElements() == 2) {
if (VTy->getElementType()->isInteger())
Elts.push_back(VectorType::get(Type::Int64Ty, 2));
else
Elts.push_back(VectorType::get(Type::DoubleTy, 2));
Bytes -= 8;
} else {
assert(VTy->getNumElements() == 4);
if (VTy->getElementType()->isInteger())
Elts.push_back(VectorType::get(Type::Int32Ty, 4));
else
Elts.push_back(VectorType::get(Type::FloatTy, 4));
Bytes -= 4;
}
} else if (llvm_x86_is_all_integer_types(Ty)) {
Elts.push_back(VectorType::get(Type::Int32Ty, 4));
Bytes -= 4;
} else {
Elts.push_back(VectorType::get(Type::FloatTy, 4));
Bytes -= 4;
}
} else if (Class[i+1] == X86_64_SSESF_CLASS) {
assert(Bytes == 12 && "Not yet handled!");
Elts.push_back(Type::DoubleTy);
Elts.push_back(Type::FloatTy);
Bytes -= 12;
} else if (Class[i+1] == X86_64_SSE_CLASS) {
Elts.push_back(Type::DoubleTy);
Elts.push_back(Type::DoubleTy);
Bytes -= 16;
} else
assert(0 && "Not yet handled!");
++i; // Already handled the next one.
} else
assert(0 && "Not yet handled!");
break;
case X86_64_SSESF_CLASS:
Elts.push_back(Type::FloatTy);
Bytes -= 4;
break;
case X86_64_SSEDF_CLASS:
Elts.push_back(Type::DoubleTy);
Bytes -= 8;
break;
case X86_64_X87_CLASS:
case X86_64_X87UP_CLASS:
case X86_64_COMPLEX_X87_CLASS:
return false;
case X86_64_NO_CLASS:
return false;
default: assert(0 && "Unexpected register class!");
}
}
return true;
}
/* On Darwin, vectors which are not MMX nor SSE should be passed as integers. */
bool llvm_x86_should_pass_vector_in_integer_regs(tree type) {
if (!TARGET_MACHO)
return false;
if (TREE_CODE(type) == VECTOR_TYPE &&
TYPE_SIZE(type) &&
TREE_CODE(TYPE_SIZE(type))==INTEGER_CST) {
if (TREE_INT_CST_LOW(TYPE_SIZE(type))==64 && TARGET_MMX)
return false;
if (TREE_INT_CST_LOW(TYPE_SIZE(type))==128 && TARGET_SSE)
return false;
}
return true;
}
/* The MMX vector v1i64 is returned in EAX and EDX on Darwin. Communicate
this by returning i64 here. Likewise, (generic) vectors such as v2i16
are returned in EAX. */
tree llvm_x86_should_return_vector_as_scalar(tree type, bool isBuiltin) {
if (TARGET_MACHO &&
!isBuiltin &&
!TARGET_64BIT &&
TREE_CODE(type) == VECTOR_TYPE &&
TYPE_SIZE(type) &&
TREE_CODE(TYPE_SIZE(type))==INTEGER_CST) {
if (TREE_INT_CST_LOW(TYPE_SIZE(type))==64 &&
TYPE_VECTOR_SUBPARTS(type)==1)
return uint64_type_node;
if (TREE_INT_CST_LOW(TYPE_SIZE(type))==32)
return uint32_type_node;
}
return 0;
}
/* MMX vectors v2i32, v4i16, v8i8, v2f32 are returned using sret on Darwin
32-bit. Vectors bigger than 128 are returned using sret. */
bool llvm_x86_should_return_vector_as_shadow(tree type, bool isBuiltin) {
if (TARGET_MACHO &&
!isBuiltin &&
!TARGET_64BIT &&
TREE_CODE(type) == VECTOR_TYPE &&
TYPE_SIZE(type) &&
TREE_CODE(TYPE_SIZE(type))==INTEGER_CST) {
if (TREE_INT_CST_LOW(TYPE_SIZE(type))==64 &&
TYPE_VECTOR_SUBPARTS(type)>1)
return true;
if (TREE_INT_CST_LOW(TYPE_SIZE(type))>128)
return true;
}
return false;
}
// llvm_suitable_multiple_ret_value_type - Return TRUE if return value
// of type TY should be returned using multiple value return instruction.
static bool llvm_suitable_multiple_ret_value_type(const Type *Ty) {
//NOTE: Work in progress. Do not open the flood gate yet.
return false;
if (!TARGET_64BIT)
return false;
const StructType *STy = dyn_cast<StructType>(Ty);
if (!STy)
return false;
unsigned NumElements = STy->getNumElements();
bool useMultipleReturnVals = true;
for (unsigned i = 0; i < NumElements; ++i) {
const Type *T = STy->getElementType(i);
if (T->isFirstClassType())
continue;
if (const ArrayType *ATy = dyn_cast<ArrayType>(T)) {
// Allow { float f[4]; } but block { float f[10]; } or { char c[4]; }
// FIXME :Double check '5'.
if (ATy->getElementType()->isFloatingPoint()
&& ATy->getNumElements() < 5)
continue;
}
return false;
}
return true;
}
// llvm_x86_scalar_type_for_struct_return - Return LLVM type if TY
// can be returned as a scalar, otherwise return NULL.
const Type *llvm_x86_scalar_type_for_struct_return(const Type *Ty) {
unsigned Size = getTargetData().getABITypeSize(Ty);
if (Size == 0)
return Type::VoidTy;
else if (Size == 1)
return Type::Int8Ty;
else if (Size == 2)
return Type::Int16Ty;
else if (Size <= 4)
return Type::Int32Ty;
// Check if Ty should be returned using multiple value return instruction.
if (llvm_suitable_multiple_ret_value_type(Ty))
return NULL;
if (Size <= 8)
return Type::Int64Ty;
else if (Size <= 16)
return IntegerType::get(128);
else if (Size <= 32)
return IntegerType::get(256);
return NULL;
}
// Return LLVM Type if TY can be returned as an aggregate, otherwise return NULL.
const Type *llvm_x86_aggr_type_for_struct_return(const Type *Ty) {
if (!llvm_suitable_multiple_ret_value_type(Ty))
return NULL;
const StructType *STy = cast<StructType>(Ty);
unsigned NumElements = STy->getNumElements();
std::vector<const Type *> ElementTypes;
for (unsigned i = 0; i < NumElements; ++i) {
const Type *T = STy->getElementType(i);
if (T->isFirstClassType()) {
ElementTypes.push_back(T);
continue;
}
const ArrayType *ATy = dyn_cast<ArrayType>(T);
assert (ATy && "Unexpected struct element type!");
assert (ATy->getElementType()->isFirstClassType()
&& "Unexpected ArrayType element type!");
unsigned size = ATy->getNumElements();
if (ATy->getElementType()->isFloatingPoint()) {
switch (size) {
case 2:
// use { <2 x float> } for struct { float[2]; }
ElementTypes.push_back(VectorType::get(ATy->getElementType(), 2));
break;
case 3:
// use { <2 x float>, float } for struct { float[3]; }
ElementTypes.push_back(VectorType::get(ATy->getElementType(), 2));
ElementTypes.push_back(ATy->getElementType());
break;
case 4:
// use { <4 x float> } for struct { float[4]; }
ElementTypes.push_back(VectorType::get(ATy->getElementType(), 4));
break;
default:
assert (0 && "Unexpected floating point array size!");
}
} else {
for (unsigned j = 0; j < size; ++j)
ElementTypes.push_back(ATy->getElementType());
}
}
return StructType::get(ElementTypes, STy->isPacked());
}
// llvm_x86_build_mrv_array_element - This is a helper function used by
// llvm_x6_build_multiple_return_value. This function builds a vector
// from the array fields of RetVal.
static Value *llvm_x86_build_mrv_array_element(const Type *STyFieldTy,
Value *RetVal,
unsigned FieldNo,
unsigned ArraySize,
IRBuilder &Builder) {
llvm::Value *Idxs[3];
Idxs[0] = ConstantInt::get(llvm::Type::Int32Ty, 0);
Idxs[1] = ConstantInt::get(llvm::Type::Int32Ty, FieldNo);
Value *R1 = UndefValue::get(STyFieldTy);
for (unsigned i = 0; i < ArraySize; ++i) {
Idxs[2] = ConstantInt::get(llvm::Type::Int32Ty, i);
Value *GEP = Builder.CreateGEP(RetVal, Idxs, Idxs+3, "mrv_gep");
Value *ElemVal = Builder.CreateLoad(GEP, "mrv");
R1 = Builder.CreateInsertElement(R1, ElemVal,
ConstantInt::get(llvm::Type::Int32Ty, i),
"mrv");
}
return R1;
}
// llvm_x86_build_multiple_return_value - Function FN returns multiple value
// where RETVAL points to the aggregate being returned. Build a RETVALS vector
// of individual values from RETVAL aggregate. RETVALS will be used by
// the client to build multiple value return instruction.
void llvm_x86_build_multiple_return_value(Function *Fn, Value *RetVal,
SmallVectorImpl <Value *> &RetVals,
IRBuilder &Builder) {
const StructType *STy = cast<StructType>(Fn->getReturnType());
const PointerType *PTy = cast<PointerType>(RetVal->getType());
const StructType *RetSTy = cast<StructType>(PTy->getElementType());
// Walk RetSTy elements and populate RetVals vector. Note, STy and RetSTy
// may not match. For example, when STy is { <2 x float> } the RetSTy is
// { float[2]; }
unsigned NumElements = RetSTy->getNumElements();
for (unsigned RNO = 0, SNO = 0; RNO < NumElements; ++RNO, ++SNO) {
const Type *ElemType = RetSTy->getElementType(RNO);
if (ElemType->isFirstClassType()) {
Value *GEP = Builder.CreateStructGEP(RetVal, RNO, "mrv_idx");
Value *ElemVal = Builder.CreateLoad(GEP, "mrv");
RetVals.push_back(ElemVal);
} else {
const ArrayType *ATy = cast<ArrayType>(ElemType);
unsigned ArraySize = ATy->getNumElements();
const VectorType *SElemTy = cast<VectorType>(STy->getElementType(SNO));
unsigned Size = SElemTy->getNumElements();
assert (ArraySize >= Size && "Invalid multiple return value type!");
Value *R = llvm_x86_build_mrv_array_element(SElemTy, RetVal, RNO,
Size, Builder);
RetVals.push_back(R);
if (ArraySize > Size) {
assert (ArraySize == Size + 1 && "Unable to build multiple return value!");
// Build remaining values.
const Type *NextTy = STy->getElementType(SNO + 1);
if (NextTy->getTypeID() == Type::FloatTyID) {
Value *Idxs[3];
Idxs[0] = ConstantInt::get(llvm::Type::Int32Ty, 0);
Idxs[1] = ConstantInt::get(llvm::Type::Int32Ty, RNO);
Idxs[2] = ConstantInt::get(llvm::Type::Int32Ty, Size + 1);
Value *GEP3 = Builder.CreateGEP(RetVal, Idxs, Idxs+3, "mrv_gep");
Value *ElemVal3 = Builder.CreateLoad(GEP3, "mrv");
RetVals.push_back(ElemVal3);
SNO++;
} else
assert ( 0 && "Unable to build multiple return value!");
}
}
}
}
// llvm_x86_extract_mrv_array_element - Helper function that help extract
// an array element from multiple return value.
//
// Here, SRC is returning multiple values. DEST's DESTFIELNO field is an array.
// Extract SRCFIELDNO's ELEMENO value and store it in DEST's FIELDNO field's
// ELEMENTNO.
//
static void llvm_x86_extract_mrv_array_element(Value *Src, Value *Dest,
unsigned SrcFieldNo,
unsigned SrcElemNo,
unsigned DestFieldNo,
unsigned DestElemNo,
IRBuilder &Builder,
bool isVolatile) {
GetResultInst *GR = Builder.CreateGetResult(Src, SrcFieldNo, "mrv_gr");
const StructType *STy = cast<StructType>(Src->getType());
llvm::Value *Idxs[3];
Idxs[0] = ConstantInt::get(llvm::Type::Int32Ty, 0);
Idxs[1] = ConstantInt::get(llvm::Type::Int32Ty, DestFieldNo);
Idxs[2] = ConstantInt::get(llvm::Type::Int32Ty, DestElemNo);
Value *GEP = Builder.CreateGEP(Dest, Idxs, Idxs+3, "mrv_gep");
if (isa<VectorType>(STy->getElementType(SrcFieldNo))) {
Value *ElemIndex = ConstantInt::get(Type::Int32Ty, SrcElemNo);
Value *GRElem = Builder.CreateExtractElement(GR, ElemIndex, "mrv");
Builder.CreateStore(GRElem, GEP, isVolatile);
} else {
Builder.CreateStore(GR, GEP, isVolatile);
}
}
// llvm_x86_extract_multiple_return_value - Extract multiple values returned
// by SRC and store them in DEST. It is expected thaty SRC and
// DEST types are StructType, but they may not match.
void llvm_x86_extract_multiple_return_value(Value *Src, Value *Dest,
bool isVolatile,
IRBuilder &Builder) {
const StructType *STy = cast<StructType>(Src->getType());
unsigned NumElements = STy->getNumElements();
const PointerType *PTy = cast<PointerType>(Dest->getType());
const StructType *DestTy = cast<StructType>(PTy->getElementType());
unsigned SNO = 0;
unsigned DNO = 0;
while (SNO < NumElements) {
const Type *DestElemType = DestTy->getElementType(DNO);
// Directly access first class values using getresult.
if (DestElemType->isFirstClassType()) {
Value *GEP = Builder.CreateStructGEP(Dest, DNO, "mrv_gep");
GetResultInst *GR = Builder.CreateGetResult(Src, SNO, "mrv_gr");
Builder.CreateStore(GR, GEP, isVolatile);
++DNO; ++SNO;
continue;
}
// Access array elements individually. Note, Src and Dest type may
// not match. For example { <2 x float>, float } and { float[3]; }
const ArrayType *ATy = cast<ArrayType>(DestElemType);
unsigned ArraySize = ATy->getNumElements();
for (unsigned di = 0, si = 0; di < ArraySize; ++di, ++si) {
llvm_x86_extract_mrv_array_element(Src, Dest, SNO, si, DNO, di,
Builder, isVolatile);
if (const VectorType *SElemTy =
dyn_cast<VectorType>(STy->getElementType(SNO))) {
unsigned NumVElem = SElemTy->getNumElements();
if (NumVElem == si + 1) {
// If extracted all elments from current Src field then
// move to next field.
si = 0;
++SNO;
}
} else {
// Copied content from current source field, so move to next field.
++SNO;
}
}
// Process next DNO element.
++DNO;
}
}
/* LLVM LOCAL end (ENTIRE FILE!) */