mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-27 14:34:58 +00:00
[Sparc] Add support for soft long double (fp128).
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189780 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
4ccfbedaed
commit
75ddb2bb34
@ -915,6 +915,22 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI,
|
||||
return Chain;
|
||||
}
|
||||
|
||||
// This functions returns true if CalleeName is a ABI function that returns
|
||||
// a long double (fp128).
|
||||
static bool isFP128ABICall(const char *CalleeName)
|
||||
{
|
||||
static const char *const ABICalls[] =
|
||||
{ "_Q_add", "_Q_sub", "_Q_mul", "_Q_div",
|
||||
"_Q_sqrt", "_Q_neg",
|
||||
"_Q_itoq", "_Q_stoq", "_Q_dtoq", "_Q_utoq",
|
||||
0
|
||||
};
|
||||
for (const char * const *I = ABICalls; I != 0; ++I)
|
||||
if (strcmp(CalleeName, *I) == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned
|
||||
SparcTargetLowering::getSRetArgSize(SelectionDAG &DAG, SDValue Callee) const
|
||||
{
|
||||
@ -925,7 +941,10 @@ SparcTargetLowering::getSRetArgSize(SelectionDAG &DAG, SDValue Callee) const
|
||||
dyn_cast<ExternalSymbolSDNode>(Callee)) {
|
||||
const Function *Fn = DAG.getMachineFunction().getFunction();
|
||||
const Module *M = Fn->getParent();
|
||||
CalleeFn = M->getFunction(E->getSymbol());
|
||||
const char *CalleeName = E->getSymbol();
|
||||
CalleeFn = M->getFunction(CalleeName);
|
||||
if (!CalleeFn && isFP128ABICall(CalleeName))
|
||||
return 16; // Return sizeof(fp128)
|
||||
}
|
||||
|
||||
if (!CalleeFn)
|
||||
@ -1428,6 +1447,47 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM)
|
||||
setOperationAction(ISD::FNEG, MVT::f128, Custom);
|
||||
setOperationAction(ISD::FABS, MVT::f128, Custom);
|
||||
}
|
||||
} else {
|
||||
// Custom legalize f128 operations.
|
||||
|
||||
setOperationAction(ISD::FADD, MVT::f128, Custom);
|
||||
setOperationAction(ISD::FSUB, MVT::f128, Custom);
|
||||
setOperationAction(ISD::FMUL, MVT::f128, Custom);
|
||||
setOperationAction(ISD::FDIV, MVT::f128, Custom);
|
||||
setOperationAction(ISD::FSQRT, MVT::f128, Custom);
|
||||
setOperationAction(ISD::FNEG, MVT::f128, Custom);
|
||||
setOperationAction(ISD::FABS, MVT::f128, Custom);
|
||||
|
||||
setOperationAction(ISD::FP_EXTEND, MVT::f128, Custom);
|
||||
setOperationAction(ISD::FP_ROUND, MVT::f64, Custom);
|
||||
setOperationAction(ISD::FP_ROUND, MVT::f32, Custom);
|
||||
|
||||
// Setup Runtime library names.
|
||||
if (Subtarget->is64Bit()) {
|
||||
setLibcallName(RTLIB::ADD_F128, "_Qp_add");
|
||||
setLibcallName(RTLIB::SUB_F128, "_Qp_sub");
|
||||
setLibcallName(RTLIB::MUL_F128, "_Qp_mul");
|
||||
setLibcallName(RTLIB::DIV_F128, "_Qp_div");
|
||||
setLibcallName(RTLIB::SQRT_F128, "_Qp_sqrt");
|
||||
setLibcallName(RTLIB::FPTOSINT_F128_I32, "_Qp_qtoi");
|
||||
setLibcallName(RTLIB::SINTTOFP_I32_F128, "_Qp_itoq");
|
||||
setLibcallName(RTLIB::FPEXT_F32_F128, "_Qp_stoq");
|
||||
setLibcallName(RTLIB::FPEXT_F64_F128, "_Qp_dtoq");
|
||||
setLibcallName(RTLIB::FPROUND_F128_F32, "_Qp_qtos");
|
||||
setLibcallName(RTLIB::FPROUND_F128_F64, "_Qp_qtod");
|
||||
} else {
|
||||
setLibcallName(RTLIB::ADD_F128, "_Q_add");
|
||||
setLibcallName(RTLIB::SUB_F128, "_Q_sub");
|
||||
setLibcallName(RTLIB::MUL_F128, "_Q_mul");
|
||||
setLibcallName(RTLIB::DIV_F128, "_Q_div");
|
||||
setLibcallName(RTLIB::SQRT_F128, "_Q_sqrt");
|
||||
setLibcallName(RTLIB::FPTOSINT_F128_I32, "_Q_qtoi");
|
||||
setLibcallName(RTLIB::SINTTOFP_I32_F128, "_Q_itoq");
|
||||
setLibcallName(RTLIB::FPEXT_F32_F128, "_Q_stoq");
|
||||
setLibcallName(RTLIB::FPEXT_F64_F128, "_Q_dtoq");
|
||||
setLibcallName(RTLIB::FPROUND_F128_F32, "_Q_qtos");
|
||||
setLibcallName(RTLIB::FPROUND_F128_F64, "_Q_qtod");
|
||||
}
|
||||
}
|
||||
|
||||
setMinFunctionAlignment(2);
|
||||
@ -1605,23 +1665,264 @@ SDValue SparcTargetLowering::LowerBlockAddress(SDValue Op,
|
||||
return makeAddress(Op, DAG);
|
||||
}
|
||||
|
||||
static SDValue LowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG) {
|
||||
SDValue
|
||||
SparcTargetLowering::LowerF128_LibCallArg(SDValue Chain, ArgListTy &Args,
|
||||
SDValue Arg, SDLoc DL,
|
||||
SelectionDAG &DAG) const {
|
||||
MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
|
||||
EVT ArgVT = Arg.getValueType();
|
||||
Type *ArgTy = ArgVT.getTypeForEVT(*DAG.getContext());
|
||||
|
||||
ArgListEntry Entry;
|
||||
Entry.Node = Arg;
|
||||
Entry.Ty = ArgTy;
|
||||
|
||||
if (ArgTy->isFP128Ty()) {
|
||||
// Create a stack object and pass the pointer to the library function.
|
||||
int FI = MFI->CreateStackObject(16, 8, false);
|
||||
SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy());
|
||||
Chain = DAG.getStore(Chain,
|
||||
DL,
|
||||
Entry.Node,
|
||||
FIPtr,
|
||||
MachinePointerInfo(),
|
||||
false,
|
||||
false,
|
||||
8);
|
||||
|
||||
Entry.Node = FIPtr;
|
||||
Entry.Ty = PointerType::getUnqual(ArgTy);
|
||||
}
|
||||
Args.push_back(Entry);
|
||||
return Chain;
|
||||
}
|
||||
|
||||
SDValue
|
||||
SparcTargetLowering::LowerF128Op(SDValue Op, SelectionDAG &DAG,
|
||||
const char *LibFuncName,
|
||||
unsigned numArgs) const {
|
||||
|
||||
ArgListTy Args;
|
||||
|
||||
MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
|
||||
|
||||
SDValue Callee = DAG.getExternalSymbol(LibFuncName, getPointerTy());
|
||||
Type *RetTy = Op.getValueType().getTypeForEVT(*DAG.getContext());
|
||||
Type *RetTyABI = RetTy;
|
||||
SDValue Chain = DAG.getEntryNode();
|
||||
SDValue RetPtr;
|
||||
|
||||
if (RetTy->isFP128Ty()) {
|
||||
// Create a Stack Object to receive the return value of type f128.
|
||||
ArgListEntry Entry;
|
||||
int RetFI = MFI->CreateStackObject(16, 8, false);
|
||||
RetPtr = DAG.getFrameIndex(RetFI, getPointerTy());
|
||||
Entry.Node = RetPtr;
|
||||
Entry.Ty = PointerType::getUnqual(RetTy);
|
||||
if (!Subtarget->is64Bit())
|
||||
Entry.isSRet = true;
|
||||
Entry.isReturned = false;
|
||||
Args.push_back(Entry);
|
||||
RetTyABI = Type::getVoidTy(*DAG.getContext());
|
||||
}
|
||||
|
||||
assert(Op->getNumOperands() >= numArgs && "Not enough operands!");
|
||||
for (unsigned i = 0, e = numArgs; i != e; ++i) {
|
||||
Chain = LowerF128_LibCallArg(Chain, Args, Op.getOperand(i), SDLoc(Op), DAG);
|
||||
}
|
||||
TargetLowering::
|
||||
CallLoweringInfo CLI(Chain,
|
||||
RetTyABI,
|
||||
false, false, false, false,
|
||||
0, CallingConv::C,
|
||||
false, false, true,
|
||||
Callee, Args, DAG, SDLoc(Op));
|
||||
std::pair<SDValue, SDValue> CallInfo = LowerCallTo(CLI);
|
||||
|
||||
// chain is in second result.
|
||||
if (RetTyABI == RetTy)
|
||||
return CallInfo.first;
|
||||
|
||||
assert (RetTy->isFP128Ty() && "Unexpected return type!");
|
||||
|
||||
Chain = CallInfo.second;
|
||||
|
||||
// Load RetPtr to get the return value.
|
||||
return DAG.getLoad(Op.getValueType(),
|
||||
SDLoc(Op),
|
||||
Chain,
|
||||
RetPtr,
|
||||
MachinePointerInfo(),
|
||||
false, false, false, 8);
|
||||
}
|
||||
|
||||
SDValue
|
||||
SparcTargetLowering::LowerF128Compare(SDValue LHS, SDValue RHS,
|
||||
unsigned &SPCC,
|
||||
SDLoc DL,
|
||||
SelectionDAG &DAG) const {
|
||||
|
||||
const char *LibCall = 0;
|
||||
bool is64Bit = Subtarget->is64Bit();
|
||||
switch(SPCC) {
|
||||
default: llvm_unreachable("Unhandled conditional code!");
|
||||
case SPCC::FCC_E : LibCall = is64Bit? "_Qp_feq" : "_Q_feq"; break;
|
||||
case SPCC::FCC_NE : LibCall = is64Bit? "_Qp_fne" : "_Q_fne"; break;
|
||||
case SPCC::FCC_L : LibCall = is64Bit? "_Qp_flt" : "_Q_flt"; break;
|
||||
case SPCC::FCC_G : LibCall = is64Bit? "_Qp_fgt" : "_Q_fgt"; break;
|
||||
case SPCC::FCC_LE : LibCall = is64Bit? "_Qp_fle" : "_Q_fle"; break;
|
||||
case SPCC::FCC_GE : LibCall = is64Bit? "_Qp_fge" : "_Q_fge"; break;
|
||||
case SPCC::FCC_UL :
|
||||
case SPCC::FCC_ULE:
|
||||
case SPCC::FCC_UG :
|
||||
case SPCC::FCC_UGE:
|
||||
case SPCC::FCC_U :
|
||||
case SPCC::FCC_O :
|
||||
case SPCC::FCC_LG :
|
||||
case SPCC::FCC_UE : LibCall = is64Bit? "_Qp_cmp" : "_Q_cmp"; break;
|
||||
}
|
||||
|
||||
SDValue Callee = DAG.getExternalSymbol(LibCall, getPointerTy());
|
||||
Type *RetTy = Type::getInt32Ty(*DAG.getContext());
|
||||
ArgListTy Args;
|
||||
SDValue Chain = DAG.getEntryNode();
|
||||
Chain = LowerF128_LibCallArg(Chain, Args, LHS, DL, DAG);
|
||||
Chain = LowerF128_LibCallArg(Chain, Args, RHS, DL, DAG);
|
||||
|
||||
TargetLowering::
|
||||
CallLoweringInfo CLI(Chain,
|
||||
RetTy,
|
||||
false, false, false, false,
|
||||
0, CallingConv::C,
|
||||
false, false, true,
|
||||
Callee, Args, DAG, DL);
|
||||
|
||||
std::pair<SDValue, SDValue> CallInfo = LowerCallTo(CLI);
|
||||
|
||||
// result is in first, and chain is in second result.
|
||||
SDValue Result = CallInfo.first;
|
||||
|
||||
switch(SPCC) {
|
||||
default: {
|
||||
SDValue RHS = DAG.getTargetConstant(0, Result.getValueType());
|
||||
SPCC = SPCC::ICC_NE;
|
||||
return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS);
|
||||
}
|
||||
case SPCC::FCC_UL : {
|
||||
SDValue Mask = DAG.getTargetConstant(1, Result.getValueType());
|
||||
Result = DAG.getNode(ISD::AND, DL, Result.getValueType(), Result, Mask);
|
||||
SDValue RHS = DAG.getTargetConstant(0, Result.getValueType());
|
||||
SPCC = SPCC::ICC_NE;
|
||||
return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS);
|
||||
}
|
||||
case SPCC::FCC_ULE: {
|
||||
SDValue RHS = DAG.getTargetConstant(2, LHS.getValueType());
|
||||
SPCC = SPCC::ICC_NE;
|
||||
return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS);
|
||||
}
|
||||
case SPCC::FCC_UG : {
|
||||
SDValue RHS = DAG.getTargetConstant(1, Result.getValueType());
|
||||
SPCC = SPCC::ICC_G;
|
||||
return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS);
|
||||
}
|
||||
case SPCC::FCC_UGE: {
|
||||
SDValue RHS = DAG.getTargetConstant(1, Result.getValueType());
|
||||
SPCC = SPCC::ICC_NE;
|
||||
return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS);
|
||||
}
|
||||
|
||||
case SPCC::FCC_U : {
|
||||
SDValue RHS = DAG.getTargetConstant(3, Result.getValueType());
|
||||
SPCC = SPCC::ICC_E;
|
||||
return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS);
|
||||
}
|
||||
case SPCC::FCC_O : {
|
||||
SDValue RHS = DAG.getTargetConstant(3, Result.getValueType());
|
||||
SPCC = SPCC::ICC_NE;
|
||||
return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS);
|
||||
}
|
||||
case SPCC::FCC_LG : {
|
||||
SDValue Mask = DAG.getTargetConstant(3, Result.getValueType());
|
||||
Result = DAG.getNode(ISD::AND, DL, Result.getValueType(), Result, Mask);
|
||||
SDValue RHS = DAG.getTargetConstant(0, Result.getValueType());
|
||||
SPCC = SPCC::ICC_NE;
|
||||
return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS);
|
||||
}
|
||||
case SPCC::FCC_UE : {
|
||||
SDValue Mask = DAG.getTargetConstant(3, Result.getValueType());
|
||||
Result = DAG.getNode(ISD::AND, DL, Result.getValueType(), Result, Mask);
|
||||
SDValue RHS = DAG.getTargetConstant(0, Result.getValueType());
|
||||
SPCC = SPCC::ICC_E;
|
||||
return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static SDValue
|
||||
LowerF128_FPEXTEND(SDValue Op, SelectionDAG &DAG,
|
||||
const SparcTargetLowering &TLI) {
|
||||
|
||||
if (Op.getOperand(0).getValueType() == MVT::f64)
|
||||
return TLI.LowerF128Op(Op, DAG,
|
||||
TLI.getLibcallName(RTLIB::FPEXT_F64_F128), 1);
|
||||
|
||||
if (Op.getOperand(0).getValueType() == MVT::f32)
|
||||
return TLI.LowerF128Op(Op, DAG,
|
||||
TLI.getLibcallName(RTLIB::FPEXT_F32_F128), 1);
|
||||
|
||||
llvm_unreachable("fpextend with non-float operand!");
|
||||
return SDValue(0, 0);
|
||||
}
|
||||
|
||||
static SDValue
|
||||
LowerF128_FPROUND(SDValue Op, SelectionDAG &DAG,
|
||||
const SparcTargetLowering &TLI) {
|
||||
// FP_ROUND on f64 and f32 are legal.
|
||||
if (Op.getOperand(0).getValueType() != MVT::f128)
|
||||
return Op;
|
||||
|
||||
if (Op.getValueType() == MVT::f64)
|
||||
return TLI.LowerF128Op(Op, DAG,
|
||||
TLI.getLibcallName(RTLIB::FPROUND_F128_F64), 1);
|
||||
if (Op.getValueType() == MVT::f32)
|
||||
return TLI.LowerF128Op(Op, DAG,
|
||||
TLI.getLibcallName(RTLIB::FPROUND_F128_F32), 1);
|
||||
|
||||
llvm_unreachable("fpround to non-float!");
|
||||
return SDValue(0, 0);
|
||||
}
|
||||
|
||||
static SDValue LowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG,
|
||||
const SparcTargetLowering &TLI,
|
||||
bool hasHardQuad) {
|
||||
SDLoc dl(Op);
|
||||
// Convert the fp value to integer in an FP register.
|
||||
assert(Op.getValueType() == MVT::i32);
|
||||
|
||||
if (Op.getOperand(0).getValueType() == MVT::f128 && !hasHardQuad)
|
||||
return TLI.LowerF128Op(Op, DAG,
|
||||
TLI.getLibcallName(RTLIB::FPTOSINT_F128_I32), 1);
|
||||
|
||||
Op = DAG.getNode(SPISD::FTOI, dl, MVT::f32, Op.getOperand(0));
|
||||
return DAG.getNode(ISD::BITCAST, dl, MVT::i32, Op);
|
||||
}
|
||||
|
||||
static SDValue LowerSINT_TO_FP(SDValue Op, SelectionDAG &DAG) {
|
||||
static SDValue LowerSINT_TO_FP(SDValue Op, SelectionDAG &DAG,
|
||||
const SparcTargetLowering &TLI,
|
||||
bool hasHardQuad) {
|
||||
SDLoc dl(Op);
|
||||
assert(Op.getOperand(0).getValueType() == MVT::i32);
|
||||
SDValue Tmp = DAG.getNode(ISD::BITCAST, dl, MVT::f32, Op.getOperand(0));
|
||||
// Convert the int value to FP in an FP register.
|
||||
if (Op.getValueType() == MVT::f128 && hasHardQuad)
|
||||
return TLI.LowerF128Op(Op, DAG,
|
||||
TLI.getLibcallName(RTLIB::SINTTOFP_I32_F128), 1);
|
||||
return DAG.getNode(SPISD::ITOF, dl, Op.getValueType(), Tmp);
|
||||
}
|
||||
|
||||
static SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) {
|
||||
static SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG,
|
||||
const SparcTargetLowering &TLI,
|
||||
bool hasHardQuad) {
|
||||
SDValue Chain = Op.getOperand(0);
|
||||
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get();
|
||||
SDValue LHS = Op.getOperand(2);
|
||||
@ -1642,15 +1943,23 @@ static SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) {
|
||||
// 32-bit compares use the icc flags, 64-bit uses the xcc flags.
|
||||
Opc = LHS.getValueType() == MVT::i32 ? SPISD::BRICC : SPISD::BRXCC;
|
||||
} else {
|
||||
CompareFlag = DAG.getNode(SPISD::CMPFCC, dl, MVT::Glue, LHS, RHS);
|
||||
if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC);
|
||||
Opc = SPISD::BRFCC;
|
||||
if (!hasHardQuad && LHS.getValueType() == MVT::f128) {
|
||||
if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC);
|
||||
CompareFlag = TLI.LowerF128Compare(LHS, RHS, SPCC, dl, DAG);
|
||||
Opc = SPISD::BRICC;
|
||||
} else {
|
||||
CompareFlag = DAG.getNode(SPISD::CMPFCC, dl, MVT::Glue, LHS, RHS);
|
||||
if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC);
|
||||
Opc = SPISD::BRFCC;
|
||||
}
|
||||
}
|
||||
return DAG.getNode(Opc, dl, MVT::Other, Chain, Dest,
|
||||
DAG.getConstant(SPCC, MVT::i32), CompareFlag);
|
||||
}
|
||||
|
||||
static SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) {
|
||||
static SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG,
|
||||
const SparcTargetLowering &TLI,
|
||||
bool hasHardQuad) {
|
||||
SDValue LHS = Op.getOperand(0);
|
||||
SDValue RHS = Op.getOperand(1);
|
||||
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
|
||||
@ -1670,9 +1979,15 @@ static SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) {
|
||||
SPISD::SELECT_ICC : SPISD::SELECT_XCC;
|
||||
if (SPCC == ~0U) SPCC = IntCondCCodeToICC(CC);
|
||||
} else {
|
||||
CompareFlag = DAG.getNode(SPISD::CMPFCC, dl, MVT::Glue, LHS, RHS);
|
||||
Opc = SPISD::SELECT_FCC;
|
||||
if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC);
|
||||
if (!hasHardQuad && LHS.getValueType() == MVT::f128) {
|
||||
if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC);
|
||||
CompareFlag = TLI.LowerF128Compare(LHS, RHS, SPCC, dl, DAG);
|
||||
Opc = SPISD::SELECT_ICC;
|
||||
} else {
|
||||
CompareFlag = DAG.getNode(SPISD::CMPFCC, dl, MVT::Glue, LHS, RHS);
|
||||
Opc = SPISD::SELECT_FCC;
|
||||
if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC);
|
||||
}
|
||||
}
|
||||
return DAG.getNode(Opc, dl, TrueVal.getValueType(), TrueVal, FalseVal,
|
||||
DAG.getConstant(SPCC, MVT::i32), CompareFlag);
|
||||
@ -1931,14 +2246,57 @@ static SDValue LowerF128Store(SDValue Op, SelectionDAG &DAG) {
|
||||
&OutChains[0], 2);
|
||||
}
|
||||
|
||||
static SDValue LowerFNEG(SDValue Op, SelectionDAG &DAG,
|
||||
const SparcTargetLowering &TLI,
|
||||
bool is64Bit) {
|
||||
if (Op.getValueType() == MVT::f64)
|
||||
return LowerF64Op(Op, DAG);
|
||||
if (Op.getValueType() == MVT::f128)
|
||||
return TLI.LowerF128Op(Op, DAG, ((is64Bit) ? "_Qp_neg" : "_Q_neg"), 1);
|
||||
return Op;
|
||||
}
|
||||
|
||||
static SDValue LowerFABS(SDValue Op, SelectionDAG &DAG, bool isV9) {
|
||||
if (Op.getValueType() == MVT::f64)
|
||||
return LowerF64Op(Op, DAG);
|
||||
if (Op.getValueType() != MVT::f128)
|
||||
return Op;
|
||||
|
||||
// Lower fabs on f128 to fabs on f64
|
||||
// fabs f128 => fabs f64:sub_even64, fmov f64:sub_odd64
|
||||
|
||||
SDLoc dl(Op);
|
||||
SDValue SrcReg128 = Op.getOperand(0);
|
||||
SDValue Hi64 = DAG.getTargetExtractSubreg(SP::sub_even64, dl, MVT::f64,
|
||||
SrcReg128);
|
||||
SDValue Lo64 = DAG.getTargetExtractSubreg(SP::sub_odd64, dl, MVT::f64,
|
||||
SrcReg128);
|
||||
if (isV9)
|
||||
Hi64 = DAG.getNode(Op.getOpcode(), dl, MVT::f64, Hi64);
|
||||
else
|
||||
Hi64 = LowerF64Op(Op, DAG);
|
||||
|
||||
SDValue DstReg128 = SDValue(DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF,
|
||||
dl, MVT::f128), 0);
|
||||
DstReg128 = DAG.getTargetInsertSubreg(SP::sub_even64, dl, MVT::f128,
|
||||
DstReg128, Hi64);
|
||||
DstReg128 = DAG.getTargetInsertSubreg(SP::sub_odd64, dl, MVT::f128,
|
||||
DstReg128, Lo64);
|
||||
return DstReg128;
|
||||
}
|
||||
|
||||
|
||||
|
||||
SDValue SparcTargetLowering::
|
||||
LowerOperation(SDValue Op, SelectionDAG &DAG) const {
|
||||
|
||||
bool hasHardQuad = Subtarget->hasHardQuad();
|
||||
bool is64Bit = Subtarget->is64Bit();
|
||||
bool isV9 = Subtarget->isV9();
|
||||
|
||||
switch (Op.getOpcode()) {
|
||||
default: llvm_unreachable("Should not custom lower this!");
|
||||
|
||||
case ISD::FNEG:
|
||||
case ISD::FABS: return LowerF64Op(Op, DAG);
|
||||
|
||||
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG, *this);
|
||||
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
|
||||
case ISD::GlobalTLSAddress:
|
||||
@ -1946,16 +2304,34 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const {
|
||||
case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG);
|
||||
case ISD::BlockAddress: return LowerBlockAddress(Op, DAG);
|
||||
case ISD::ConstantPool: return LowerConstantPool(Op, DAG);
|
||||
case ISD::FP_TO_SINT: return LowerFP_TO_SINT(Op, DAG);
|
||||
case ISD::SINT_TO_FP: return LowerSINT_TO_FP(Op, DAG);
|
||||
case ISD::BR_CC: return LowerBR_CC(Op, DAG);
|
||||
case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG);
|
||||
case ISD::FP_TO_SINT: return LowerFP_TO_SINT(Op, DAG, *this,
|
||||
hasHardQuad);
|
||||
case ISD::SINT_TO_FP: return LowerSINT_TO_FP(Op, DAG, *this,
|
||||
hasHardQuad);
|
||||
case ISD::BR_CC: return LowerBR_CC(Op, DAG, *this,
|
||||
hasHardQuad);
|
||||
case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG, *this,
|
||||
hasHardQuad);
|
||||
case ISD::VASTART: return LowerVASTART(Op, DAG, *this);
|
||||
case ISD::VAARG: return LowerVAARG(Op, DAG);
|
||||
case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG);
|
||||
|
||||
case ISD::LOAD: return LowerF128Load(Op, DAG);
|
||||
case ISD::STORE: return LowerF128Store(Op, DAG);
|
||||
case ISD::FADD: return LowerF128Op(Op, DAG,
|
||||
getLibcallName(RTLIB::ADD_F128), 2);
|
||||
case ISD::FSUB: return LowerF128Op(Op, DAG,
|
||||
getLibcallName(RTLIB::SUB_F128), 2);
|
||||
case ISD::FMUL: return LowerF128Op(Op, DAG,
|
||||
getLibcallName(RTLIB::MUL_F128), 2);
|
||||
case ISD::FDIV: return LowerF128Op(Op, DAG,
|
||||
getLibcallName(RTLIB::DIV_F128), 2);
|
||||
case ISD::FSQRT: return LowerF128Op(Op, DAG,
|
||||
getLibcallName(RTLIB::SQRT_F128),1);
|
||||
case ISD::FNEG: return LowerFNEG(Op, DAG, *this, is64Bit);
|
||||
case ISD::FABS: return LowerFABS(Op, DAG, isV9);
|
||||
case ISD::FP_EXTEND: return LowerF128_FPEXTEND(Op, DAG, *this);
|
||||
case ISD::FP_ROUND: return LowerF128_FPROUND(Op, DAG, *this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1972,11 +2348,13 @@ SparcTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
|
||||
case SP::SELECT_CC_Int_ICC:
|
||||
case SP::SELECT_CC_FP_ICC:
|
||||
case SP::SELECT_CC_DFP_ICC:
|
||||
case SP::SELECT_CC_QFP_ICC:
|
||||
BROpcode = SP::BCOND;
|
||||
break;
|
||||
case SP::SELECT_CC_Int_FCC:
|
||||
case SP::SELECT_CC_FP_FCC:
|
||||
case SP::SELECT_CC_DFP_FCC:
|
||||
case SP::SELECT_CC_QFP_FCC:
|
||||
BROpcode = SP::FBCOND;
|
||||
break;
|
||||
}
|
||||
|
@ -127,6 +127,23 @@ namespace llvm {
|
||||
SDValue makeHiLoPair(SDValue Op, unsigned HiTF, unsigned LoTF,
|
||||
SelectionDAG &DAG) const;
|
||||
SDValue makeAddress(SDValue Op, SelectionDAG &DAG) const;
|
||||
|
||||
SDValue LowerF128_LibCallArg(SDValue Chain, ArgListTy &Args,
|
||||
SDValue Arg, SDLoc DL,
|
||||
SelectionDAG &DAG) const;
|
||||
SDValue LowerF128Op(SDValue Op, SelectionDAG &DAG,
|
||||
const char *LibFuncName,
|
||||
unsigned numArgs) const;
|
||||
SDValue LowerF128Compare(SDValue LHS, SDValue RHS,
|
||||
unsigned &SPCC,
|
||||
SDLoc DL,
|
||||
SelectionDAG &DAG) const;
|
||||
|
||||
bool ShouldShrinkFPConstant(EVT VT) const {
|
||||
// Do not shrink FP constpool if VT == MVT::f128.
|
||||
// (ldd, call _Q_fdtoq) is more expensive than two ldds.
|
||||
return VT != MVT::f128;
|
||||
}
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
|
@ -267,6 +267,11 @@ let Uses = [ICC], usesCustomInserter = 1 in {
|
||||
: Pseudo<(outs DFPRegs:$dst), (ins DFPRegs:$T, DFPRegs:$F, i32imm:$Cond),
|
||||
"; SELECT_CC_DFP_ICC PSEUDO!",
|
||||
[(set f64:$dst, (SPselecticc f64:$T, f64:$F, imm:$Cond))]>;
|
||||
|
||||
def SELECT_CC_QFP_ICC
|
||||
: Pseudo<(outs QFPRegs:$dst), (ins QFPRegs:$T, QFPRegs:$F, i32imm:$Cond),
|
||||
"; SELECT_CC_QFP_ICC PSEUDO!",
|
||||
[(set f128:$dst, (SPselecticc f128:$T, f128:$F, imm:$Cond))]>;
|
||||
}
|
||||
|
||||
let usesCustomInserter = 1, Uses = [FCC] in {
|
||||
@ -284,6 +289,10 @@ let usesCustomInserter = 1, Uses = [FCC] in {
|
||||
: Pseudo<(outs DFPRegs:$dst), (ins DFPRegs:$T, DFPRegs:$F, i32imm:$Cond),
|
||||
"; SELECT_CC_DFP_FCC PSEUDO!",
|
||||
[(set f64:$dst, (SPselectfcc f64:$T, f64:$F, imm:$Cond))]>;
|
||||
def SELECT_CC_QFP_FCC
|
||||
: Pseudo<(outs QFPRegs:$dst), (ins QFPRegs:$T, QFPRegs:$F, i32imm:$Cond),
|
||||
"; SELECT_CC_QFP_FCC PSEUDO!",
|
||||
[(set f128:$dst, (SPselectfcc f128:$T, f128:$F, imm:$Cond))]>;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,16 +1,30 @@
|
||||
; RUN: llc < %s -march=sparc -mattr=hard-quad-float | FileCheck %s
|
||||
; RUN: llc < %s -march=sparc -mattr=hard-quad-float | FileCheck %s --check-prefix=HARD
|
||||
; RUN: llc < %s -march=sparc -mattr=-hard-quad-float | FileCheck %s --check-prefix=SOFT
|
||||
|
||||
; CHECK-LABEL: f128_ops
|
||||
; CHECK: ldd
|
||||
; CHECK: ldd
|
||||
; CHECK: ldd
|
||||
; CHECK: ldd
|
||||
; CHECK: faddq [[R0:.+]], [[R1:.+]], [[R2:.+]]
|
||||
; CHECK: fsubq [[R2]], [[R3:.+]], [[R4:.+]]
|
||||
; CHECK: fmulq [[R4]], [[R5:.+]], [[R6:.+]]
|
||||
; CHECK: fdivq [[R6]], [[R2]]
|
||||
; CHECK: std
|
||||
; CHECK: std
|
||||
|
||||
; HARD-LABEL: f128_ops
|
||||
; HARD: ldd
|
||||
; HARD: ldd
|
||||
; HARD: ldd
|
||||
; HARD: ldd
|
||||
; HARD: faddq [[R0:.+]], [[R1:.+]], [[R2:.+]]
|
||||
; HARD: fsubq [[R2]], [[R3:.+]], [[R4:.+]]
|
||||
; HARD: fmulq [[R4]], [[R5:.+]], [[R6:.+]]
|
||||
; HARD: fdivq [[R6]], [[R2]]
|
||||
; HARD: std
|
||||
; HARD: std
|
||||
|
||||
; SOFT-LABEL: f128_ops
|
||||
; SOFT: ldd
|
||||
; SOFT: ldd
|
||||
; SOFT: ldd
|
||||
; SOFT: ldd
|
||||
; SOFT: call _Q_add
|
||||
; SOFT: call _Q_sub
|
||||
; SOFT: call _Q_mul
|
||||
; SOFT: call _Q_div
|
||||
; SOFT: std
|
||||
; SOFT: std
|
||||
|
||||
define void @f128_ops(fp128* noalias sret %scalar.result, fp128* byval %a, fp128* byval %b, fp128* byval %c, fp128* byval %d) {
|
||||
entry:
|
||||
@ -26,12 +40,19 @@ entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: f128_spill
|
||||
; CHECK: std %f{{.+}}, [%[[S0:.+]]]
|
||||
; CHECK: std %f{{.+}}, [%[[S1:.+]]]
|
||||
; CHECK-DAG: ldd [%[[S0]]], %f{{.+}}
|
||||
; CHECK-DAG: ldd [%[[S1]]], %f{{.+}}
|
||||
; CHECK: jmp
|
||||
; HARD-LABEL: f128_spill
|
||||
; HARD: std %f{{.+}}, [%[[S0:.+]]]
|
||||
; HARD: std %f{{.+}}, [%[[S1:.+]]]
|
||||
; HARD-DAG: ldd [%[[S0]]], %f{{.+}}
|
||||
; HARD-DAG: ldd [%[[S1]]], %f{{.+}}
|
||||
; HARD: jmp
|
||||
|
||||
; SOFT-LABEL: f128_spill
|
||||
; SOFT: std %f{{.+}}, [%[[S0:.+]]]
|
||||
; SOFT: std %f{{.+}}, [%[[S1:.+]]]
|
||||
; SOFT-DAG: ldd [%[[S0]]], %f{{.+}}
|
||||
; SOFT-DAG: ldd [%[[S1]]], %f{{.+}}
|
||||
; SOFT: jmp
|
||||
|
||||
define void @f128_spill(fp128* noalias sret %scalar.result, fp128* byval %a) {
|
||||
entry:
|
||||
@ -40,3 +61,18 @@ entry:
|
||||
store fp128 %0, fp128* %scalar.result, align 8
|
||||
ret void
|
||||
}
|
||||
|
||||
; HARD-LABEL: f128_compare
|
||||
; HARD: fcmpq
|
||||
|
||||
; SOFT-LABEL: f128_compare
|
||||
; SOFT: _Q_cmp
|
||||
|
||||
define i32 @f128_compare(fp128* byval %f0, fp128* byval %f1, i32 %a, i32 %b) {
|
||||
entry:
|
||||
%0 = load fp128* %f0, align 8
|
||||
%1 = load fp128* %f1, align 8
|
||||
%cond = fcmp ult fp128 %0, %1
|
||||
%ret = select i1 %cond, i32 %a, i32 %b
|
||||
ret i32 %ret
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user