#include "llvm-abi.h"
#include "llvm-internal.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/Intrinsics.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
extern "C" {
#include "toplev.h"
}
static bool isSVR4ABI() {
#if defined(POWERPC_LINUX) && (TARGET_64BIT == 0)
return true;
#else
return false;
#endif
}
static LLVMContext &Context = getGlobalContext();
static void MergeIntPtrOperand(TreeToLLVM *TTL,
unsigned OpNum, Intrinsic::ID IID,
const Type *ResultType,
std::vector<Value*> &Ops,
LLVMBuilder &Builder, Value *&Result) {
const Type *VoidPtrTy = PointerType::getUnqual(Type::getInt8Ty(Context));
Function *IntFn = Intrinsic::getDeclaration(TheModule, IID);
Value *Offset = Ops[OpNum];
Value *Ptr = Ops[OpNum + 1];
Ptr = TTL->CastToType(Instruction::BitCast, Ptr, VoidPtrTy);
if (!isa<Constant>(Offset) || !cast<Constant>(Offset)->isNullValue())
Ptr = Builder.CreateGEP(Ptr, Offset, "tmp");
Ops.erase(Ops.begin() + OpNum);
Ops[OpNum] = Ptr;
Value *V = Builder.CreateCall(IntFn, &Ops[0], &Ops[0]+Ops.size());
if (V->getType() != Type::getVoidTy(Context)) {
V->setName("tmp");
Result = V;
}
}
static int GetAltivecTypeNumFromType(const Type *Ty) {
return (Ty->isIntegerTy(32) ? 0 : \
(Ty->isIntegerTy(16) ? 1 : \
(Ty->isIntegerTy(8) ? 2 : \
((Ty == Type::getFloatTy(Context)) ? 3 : -1))));
}
bool TreeToLLVM::TargetIntrinsicLower(tree exp,
unsigned FnCode,
const MemRef *DestLoc,
Value *&Result,
const Type *ResultType,
std::vector<Value*> &Ops) {
switch (FnCode) {
default: break;
case ALTIVEC_BUILTIN_VADDFP:
Result = Builder.CreateFAdd(Ops[0], Ops[1], "tmp");
return true;
case ALTIVEC_BUILTIN_VADDUBM:
case ALTIVEC_BUILTIN_VADDUHM:
case ALTIVEC_BUILTIN_VADDUWM:
Result = Builder.CreateAdd(Ops[0], Ops[1], "tmp");
return true;
case ALTIVEC_BUILTIN_VSUBFP:
Result = Builder.CreateFSub(Ops[0], Ops[1], "tmp");
return true;
case ALTIVEC_BUILTIN_VSUBUBM:
case ALTIVEC_BUILTIN_VSUBUHM:
case ALTIVEC_BUILTIN_VSUBUWM:
Result = Builder.CreateSub(Ops[0], Ops[1], "tmp");
return true;
case ALTIVEC_BUILTIN_VAND:
Result = Builder.CreateAnd(Ops[0], Ops[1], "tmp");
return true;
case ALTIVEC_BUILTIN_VANDC:
Ops[1] = Builder.CreateNot(Ops[1], "tmp");
Result = Builder.CreateAnd(Ops[0], Ops[1], "tmp");
return true;
case ALTIVEC_BUILTIN_VOR:
Result = Builder.CreateOr(Ops[0], Ops[1], "tmp");
return true;
case ALTIVEC_BUILTIN_VNOR:
Result = Builder.CreateOr(Ops[0], Ops[1], "tmp");
Result = Builder.CreateNot(Result, "tmp");
return true;
case ALTIVEC_BUILTIN_VXOR:
Result = Builder.CreateXor(Ops[0], Ops[1], "tmp");
return true;
case ALTIVEC_BUILTIN_LVSL:
MergeIntPtrOperand(this, 0, Intrinsic::ppc_altivec_lvsl,
ResultType, Ops, Builder, Result);
return true;
case ALTIVEC_BUILTIN_LVSR:
MergeIntPtrOperand(this, 0, Intrinsic::ppc_altivec_lvsr,
ResultType, Ops, Builder, Result);
return true;
case ALTIVEC_BUILTIN_LVX:
MergeIntPtrOperand(this, 0, Intrinsic::ppc_altivec_lvx,
ResultType, Ops, Builder, Result);
return true;
case ALTIVEC_BUILTIN_LVXL:
MergeIntPtrOperand(this, 0, Intrinsic::ppc_altivec_lvxl,
ResultType, Ops, Builder, Result);
return true;
case ALTIVEC_BUILTIN_LVEBX:
MergeIntPtrOperand(this, 0, Intrinsic::ppc_altivec_lvebx,
ResultType, Ops, Builder, Result);
return true;
case ALTIVEC_BUILTIN_LVEHX:
MergeIntPtrOperand(this, 0, Intrinsic::ppc_altivec_lvehx,
ResultType, Ops, Builder, Result);
return true;
case ALTIVEC_BUILTIN_LVEWX:
MergeIntPtrOperand(this, 0, Intrinsic::ppc_altivec_lvewx,
ResultType, Ops, Builder, Result);
return true;
case ALTIVEC_BUILTIN_STVX:
MergeIntPtrOperand(this, 1, Intrinsic::ppc_altivec_stvx,
ResultType, Ops, Builder, Result);
return true;
case ALTIVEC_BUILTIN_STVEBX:
MergeIntPtrOperand(this, 1, Intrinsic::ppc_altivec_stvebx,
ResultType, Ops, Builder, Result);
return true;
case ALTIVEC_BUILTIN_STVEHX:
MergeIntPtrOperand(this, 1, Intrinsic::ppc_altivec_stvehx,
ResultType, Ops, Builder, Result);
return true;
case ALTIVEC_BUILTIN_STVEWX:
MergeIntPtrOperand(this, 1, Intrinsic::ppc_altivec_stvewx,
ResultType, Ops, Builder, Result);
return true;
case ALTIVEC_BUILTIN_STVXL:
MergeIntPtrOperand(this, 1, Intrinsic::ppc_altivec_stvxl,
ResultType, Ops, Builder, Result);
return true;
case ALTIVEC_BUILTIN_VSPLTISB:
if (Constant *Elt = dyn_cast<ConstantInt>(Ops[0])) {
Elt = ConstantExpr::getIntegerCast(Elt, Type::getInt8Ty(Context), true);
Result = BuildVector(Elt, Elt, Elt, Elt, Elt, Elt, Elt, Elt,
Elt, Elt, Elt, Elt, Elt, Elt, Elt, Elt, NULL);
} else {
error("%Helement must be an immediate", &EXPR_LOCATION(exp));
Result = UndefValue::get(VectorType::get(Type::getInt8Ty(Context), 16));
}
return true;
case ALTIVEC_BUILTIN_VSPLTISH:
if (Constant *Elt = dyn_cast<ConstantInt>(Ops[0])) {
Elt = ConstantExpr::getIntegerCast(Elt, Type::getInt16Ty(Context), true);
Result = BuildVector(Elt, Elt, Elt, Elt, Elt, Elt, Elt, Elt, NULL);
} else {
error("%Helement must be an immediate", &EXPR_LOCATION(exp));
Result = UndefValue::get(VectorType::get(Type::getInt16Ty(Context), 8));
}
return true;
case ALTIVEC_BUILTIN_VSPLTISW:
if (Constant *Elt = dyn_cast<ConstantInt>(Ops[0])) {
Elt = ConstantExpr::getIntegerCast(Elt, Type::getInt32Ty(Context), true);
Result = BuildVector(Elt, Elt, Elt, Elt, NULL);
} else {
error("%Hmask must be an immediate", &EXPR_LOCATION(exp));
Result = UndefValue::get(VectorType::get(Type::getInt32Ty(Context), 4));
}
return true;
case ALTIVEC_BUILTIN_VSPLTB:
if (ConstantInt *Elt = dyn_cast<ConstantInt>(Ops[1])) {
int EV = Elt->getZExtValue();
Result = BuildVectorShuffle(Ops[0], Ops[0],
EV, EV, EV, EV, EV, EV, EV, EV,
EV, EV, EV, EV, EV, EV, EV, EV);
} else {
error("%Helement number must be an immediate", &EXPR_LOCATION(exp));
Result = Ops[0];
}
return true;
case ALTIVEC_BUILTIN_VSPLTH:
if (ConstantInt *Elt = dyn_cast<ConstantInt>(Ops[1])) {
int EV = Elt->getZExtValue();
if (EV>7 && EV<=31)
EV = EV%8;
Result = BuildVectorShuffle(Ops[0], Ops[0],
EV, EV, EV, EV, EV, EV, EV, EV);
} else {
error("%Helement number must be an immediate", &EXPR_LOCATION(exp));
Result = Ops[0];
}
return true;
case ALTIVEC_BUILTIN_VSPLTW:
if (ConstantInt *Elt = dyn_cast<ConstantInt>(Ops[1])) {
int EV = Elt->getZExtValue();
if (EV>3 && EV<=31)
EV = EV%4;
Result = BuildVectorShuffle(Ops[0], Ops[0], EV, EV, EV, EV);
} else {
error("%Helement number must be an immediate", &EXPR_LOCATION(exp));
Result = Ops[0];
}
return true;
case ALTIVEC_BUILTIN_VSLDOI_16QI:
case ALTIVEC_BUILTIN_VSLDOI_8HI:
case ALTIVEC_BUILTIN_VSLDOI_4SI:
case ALTIVEC_BUILTIN_VSLDOI_4SF:
if (ConstantInt *Elt = dyn_cast<ConstantInt>(Ops[2])) {
unsigned Amt = Elt->getZExtValue() & 15;
VectorType *v16i8 = VectorType::get(Type::getInt8Ty(Context), 16);
Ops[0] = Builder.CreateBitCast(Ops[0], v16i8, "tmp");
Ops[1] = Builder.CreateBitCast(Ops[1], v16i8, "tmp");
Result = BuildVectorShuffle(Ops[0], Ops[1],
Amt, Amt+1, Amt+2, Amt+3,
Amt+4, Amt+5, Amt+6, Amt+7,
Amt+8, Amt+9, Amt+10, Amt+11,
Amt+12, Amt+13, Amt+14, Amt+15);
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
} else {
error("%Hshift amount must be an immediate", &EXPR_LOCATION(exp));
Result = Ops[0];
}
return true;
case ALTIVEC_BUILTIN_VPKUHUM:
Ops[0] = Builder.CreateBitCast(Ops[0], ResultType, "tmp");
Ops[1] = Builder.CreateBitCast(Ops[1], ResultType, "tmp");
Result = BuildVectorShuffle(Ops[0], Ops[1], 1, 3, 5, 7, 9, 11, 13, 15,
17, 19, 21, 23, 25, 27, 29, 31);
return true;
case ALTIVEC_BUILTIN_VPKUWUM:
Ops[0] = Builder.CreateBitCast(Ops[0], ResultType, "tmp");
Ops[1] = Builder.CreateBitCast(Ops[1], ResultType, "tmp");
Result = BuildVectorShuffle(Ops[0], Ops[1], 1, 3, 5, 7, 9, 11, 13, 15);
return true;
case ALTIVEC_BUILTIN_VMRGHB:
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 ALTIVEC_BUILTIN_VMRGHH:
Result = BuildVectorShuffle(Ops[0], Ops[1], 0, 8, 1, 9, 2, 10, 3, 11);
return true;
case ALTIVEC_BUILTIN_VMRGHW:
Result = BuildVectorShuffle(Ops[0], Ops[1], 0, 4, 1, 5);
return true;
case ALTIVEC_BUILTIN_VMRGLB:
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 ALTIVEC_BUILTIN_VMRGLH:
Result = BuildVectorShuffle(Ops[0], Ops[1], 4, 12, 5, 13, 6, 14, 7, 15);
return true;
case ALTIVEC_BUILTIN_VMRGLW:
Result = BuildVectorShuffle(Ops[0], Ops[1], 2, 6, 3, 7);
return true;
case ALTIVEC_BUILTIN_ABS_V4SF: {
VectorType *v4i32 = VectorType::get(Type::getInt32Ty(Context), 4);
Ops[0] = Builder.CreateBitCast(Ops[0], v4i32, "tmp");
Constant *C = ConstantInt::get(Type::getInt32Ty(Context), 0x7FFFFFFF);
C = ConstantVector::get(std::vector<Constant*>(4, C));
Result = Builder.CreateAnd(Ops[0], C, "tmp");
Result = Builder.CreateBitCast(Result, ResultType, "tmp");
return true;
}
case ALTIVEC_BUILTIN_ABS_V4SI:
case ALTIVEC_BUILTIN_ABS_V8HI:
case ALTIVEC_BUILTIN_ABS_V16QI: { Result = Builder.CreateNeg(Ops[0], "tmp");
static const Intrinsic::ID smax_iid[3] = {
Intrinsic::ppc_altivec_vmaxsw,
Intrinsic::ppc_altivec_vmaxsh,
Intrinsic::ppc_altivec_vmaxsb
};
const VectorType *PTy = cast<VectorType>(ResultType);
unsigned N = GetAltivecTypeNumFromType(PTy->getElementType());
Function *smax = Intrinsic::getDeclaration(TheModule, smax_iid[N]);
Value *ActualOps[] = { Ops[0], Result };
Result = Builder.CreateCall(smax, ActualOps, ActualOps+2, "tmp");
return true;
}
case ALTIVEC_BUILTIN_ABSS_V4SI:
case ALTIVEC_BUILTIN_ABSS_V8HI:
case ALTIVEC_BUILTIN_ABSS_V16QI: { static const Intrinsic::ID smax_iid[3] = {
Intrinsic::ppc_altivec_vmaxsw,
Intrinsic::ppc_altivec_vmaxsh,
Intrinsic::ppc_altivec_vmaxsb
};
static const Intrinsic::ID subss_iid[3] = {
Intrinsic::ppc_altivec_vsubsws,
Intrinsic::ppc_altivec_vsubshs,
Intrinsic::ppc_altivec_vsubsbs
};
const VectorType *PTy = cast<VectorType>(ResultType);
unsigned N = GetAltivecTypeNumFromType(PTy->getElementType());
Function *smax = Intrinsic::getDeclaration(TheModule, smax_iid[N]);
Function *subss = Intrinsic::getDeclaration(TheModule, subss_iid[N]);
Value *ActualOps[] = {Constant::getNullValue(ResultType), Ops[0] };
Result = Builder.CreateCall(subss, ActualOps, ActualOps+2, "tmp");
ActualOps[0] = Ops[0];
ActualOps[1] = Result;
Result = Builder.CreateCall(smax, ActualOps, ActualOps+2, "tmp");
return true;
}
case ALTIVEC_BUILTIN_VPERM_4SI:
case ALTIVEC_BUILTIN_VPERM_4SF:
case ALTIVEC_BUILTIN_VPERM_8HI:
case ALTIVEC_BUILTIN_VPERM_16QI: {
const Type *VecTy = VectorType::get(Type::getInt32Ty(Context), 4);
Value *Op0 = CastToType(Instruction::BitCast, Ops[0], VecTy);
Value *Op1 = CastToType(Instruction::BitCast, Ops[1], VecTy);
Value *ActualOps[] = { Op0, Op1, Ops[2]};
Result = Builder.CreateCall(Intrinsic::getDeclaration(TheModule,
Intrinsic::ppc_altivec_vperm),
ActualOps, ActualOps+3, "tmp");
Result = CastToType(Instruction::BitCast, Result, Ops[0]->getType());
return true;
}
case ALTIVEC_BUILTIN_VSEL_4SI:
case ALTIVEC_BUILTIN_VSEL_4SF:
case ALTIVEC_BUILTIN_VSEL_8HI:
case ALTIVEC_BUILTIN_VSEL_16QI: {
const Type *VecTy = VectorType::get(Type::getInt32Ty(Context), 4);
Value *Op0 = CastToType(Instruction::BitCast, Ops[0], VecTy);
Value *Op1 = CastToType(Instruction::BitCast, Ops[1], VecTy);
Value *Op2 = CastToType(Instruction::BitCast, Ops[2], VecTy);
Value *ActualOps[] = { Op0, Op1, Op2 };
Result = Builder.CreateCall(Intrinsic::getDeclaration(TheModule,
Intrinsic::ppc_altivec_vsel),
ActualOps, ActualOps+3, "tmp");
Result = CastToType(Instruction::BitCast, Result, Ops[0]->getType());
return true;
}
}
return false;
}
static unsigned count_num_registers_uses(std::vector<const Type*> &ScalarElts) {
unsigned NumGPRs = 0;
for (unsigned i = 0, e = ScalarElts.size(); i != e; ++i) {
if (NumGPRs >= 8)
break;
const Type *Ty = ScalarElts[i];
if (const VectorType *VTy = dyn_cast<VectorType>(Ty)) {
abort();
} else if (Ty->isPointerTy()) {
NumGPRs++;
} else if (Ty->isIntegerTy()) {
unsigned TypeSize = Ty->getPrimitiveSizeInBits();
unsigned NumRegs = (TypeSize + 31) / 32;
NumGPRs += NumRegs;
} else if (Ty->isVoidTy()) {
;
} else {
assert(Ty->isFloatingPointTy() && Ty->isPrimitiveType() &&
"Expecting a floating point primitive type!");
}
}
return NumGPRs < 8 ? NumGPRs : 8;
}
bool llvm_rs6000_try_pass_aggregate_custom(tree type,
std::vector<const Type*> &ScalarElts,
const CallingConv::ID &CC,
struct DefaultABIClient* C) {
if (!isSVR4ABI())
return false;
const unsigned NumArgRegs = 8;
unsigned NumGPR = count_num_registers_uses(ScalarElts);
const Type *Ty = ConvertType(type);
const Type* Int32Ty = Type::getInt32Ty(getGlobalContext());
if (Ty->isSingleValueType()) {
if (Ty->isIntegerTy()) {
unsigned TypeSize = Ty->getPrimitiveSizeInBits();
unsigned NumRegs = (TypeSize + 31) / 32;
if (TypeSize == 64 && (NumGPR % 2) == 1) {
NumGPR++;
ScalarElts.push_back(Int32Ty);
C->HandlePad(Int32Ty);
}
if (NumGPR > (NumArgRegs - NumRegs)) {
for (unsigned int i = 0; i < NumArgRegs - NumGPR; ++i) {
ScalarElts.push_back(Int32Ty);
C->HandlePad(Int32Ty);
}
}
} else if (!(Ty->isFloatingPointTy() ||
Ty->isVectorTy() ||
Ty->isPointerTy())) {
abort();
}
C->HandleScalarArgument(Ty, type);
ScalarElts.push_back(Ty);
return true;
}
if (TREE_CODE(type) == COMPLEX_TYPE) {
unsigned SrcSize = int_size_in_bytes(type);
unsigned NumRegs = (SrcSize + 3) / 4;
std::vector<const Type*> Elts;
if (SrcSize == 8) {
if (NumGPR % 2 == 1) {
NumGPR++;
ScalarElts.push_back(Int32Ty);
C->HandlePad(Int32Ty);
}
}
if (NumGPR > (NumArgRegs - NumRegs)) {
for (unsigned int i = 0; i < NumArgRegs - NumGPR; ++i) {
ScalarElts.push_back(Int32Ty);
C->HandlePad(Int32Ty);
}
}
for (unsigned int i = 0; i < NumRegs; ++i) {
Elts.push_back(Int32Ty);
}
const StructType *STy = StructType::get(getGlobalContext(), Elts, false);
for (unsigned int i = 0; i < NumRegs; ++i) {
C->EnterField(i, STy);
C->HandleScalarArgument(Int32Ty, 0);
ScalarElts.push_back(Int32Ty);
C->ExitField();
}
return true;
}
return false;
}
bool llvm_rs6000_should_pass_aggregate_byval(tree TreeType, const Type *Ty) {
if (TARGET_64BIT)
return false;
HOST_WIDE_INT Bytes = (TYPE_MODE(TreeType) == BLKmode) ?
int_size_in_bytes(TreeType) :
(int) GET_MODE_SIZE(TYPE_MODE(TreeType));
if (isSVR4ABI() && (TREE_CODE(TreeType) == COMPLEX_TYPE))
return false;
if (Bytes == 0)
return false;
if (isSVR4ABI())
return true;
if (Bytes <= 0 || Bytes > 16)
return true;
const StructType *STy = dyn_cast<StructType>(Ty);
if (!STy) return true;
tree tType = isSingleElementStructOrArray(TreeType, true, false);
if (tType && int_size_in_bytes(tType)==Bytes && TYPE_MODE(tType)!=TFmode &&
(TREE_CODE(tType)!=VECTOR_TYPE || Bytes==16))
return false;
return true;
}
bool
llvm_rs6000_should_pass_aggregate_in_mixed_regs(tree TreeType, const Type* Ty,
std::vector<const Type*>&Elts) {
if (TARGET_64BIT)
return false;
HOST_WIDE_INT SrcSize = int_size_in_bytes(TreeType);
if (isSVR4ABI() && TREE_CODE(TreeType) == COMPLEX_TYPE) {
switch (SrcSize) {
default:
abort();
case 32:
Elts.push_back(Type::getInt32Ty(Context));
Elts.push_back(Type::getInt32Ty(Context));
Elts.push_back(Type::getInt32Ty(Context));
Elts.push_back(Type::getInt32Ty(Context));
case 16:
Elts.push_back(Type::getInt32Ty(Context));
Elts.push_back(Type::getInt32Ty(Context));
Elts.push_back(Type::getInt32Ty(Context));
Elts.push_back(Type::getInt32Ty(Context));
break;
case 8:
Elts.push_back(Type::getInt64Ty(Context));
break;
case 4:
case 2:
Elts.push_back(Type::getInt32Ty(Context));
break;
}
return true;
}
if (isSVR4ABI())
return false;
if (SrcSize <= 0 || SrcSize > 16)
return false;
const StructType *STy = dyn_cast<StructType>(Ty);
if (!STy) return false;
tree tType = isSingleElementStructOrArray(TreeType, true, false);
if (tType && int_size_in_bytes(tType)==SrcSize && TYPE_MODE(tType)!=TFmode &&
(TREE_CODE(tType)!=VECTOR_TYPE || SrcSize==16)) {
Elts.push_back(ConvertType(tType));
return true;
}
Elts.clear();
return false;
}
bool llvm_rs6000_should_pass_vector_in_integer_regs(tree type) {
if (!TARGET_64BIT &&
TREE_CODE(type) == VECTOR_TYPE &&
TYPE_SIZE(type) && TREE_CODE(TYPE_SIZE(type))==INTEGER_CST &&
TREE_INT_CST_LOW(TYPE_SIZE(type)) != 128)
return true;
return false;
}
tree llvm_rs6000_should_return_vector_as_scalar(tree type,
bool isBuiltin ATTRIBUTE_UNUSED) {
if (!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))==32)
return uint32_type_node;
else if (TREE_INT_CST_LOW(TYPE_SIZE(type))==64)
return uint64_type_node;
}
return 0;
}
bool llvm_rs6000_should_return_vector_as_shadow(tree type,
bool isBuiltin ATTRIBUTE_UNUSED) {
if (!TARGET_64BIT &&
TREE_CODE(type) == VECTOR_TYPE &&
TYPE_SIZE(type) &&
TREE_CODE(TYPE_SIZE(type))==INTEGER_CST &&
TREE_INT_CST_LOW(TYPE_SIZE(type))>64 &&
TREE_INT_CST_LOW(TYPE_SIZE(type))!=128)
return true;
return false;
}