2011-01-12 11:18:21 +08:00
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
//===-- SparcISelLowering.cpp - Sparc DAG Lowering Implementation ---------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the interfaces that Sparc uses to lower LLVM code into a
|
|
|
|
// selection DAG.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "SparcISelLowering.h"
|
|
|
|
#include "SparcTargetMachine.h"
|
2010-04-17 22:41:14 +08:00
|
|
|
#include "SparcMachineFunctionInfo.h"
|
2011-02-21 11:42:44 +08:00
|
|
|
#include "llvm/DerivedTypes.h"
|
2008-03-17 11:21:36 +08:00
|
|
|
#include "llvm/Function.h"
|
2011-02-21 11:42:44 +08:00
|
|
|
#include "llvm/Module.h"
|
2008-03-17 13:41:48 +08:00
|
|
|
#include "llvm/CodeGen/CallingConvLower.h"
|
2008-03-17 11:21:36 +08:00
|
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
|
|
#include "llvm/CodeGen/SelectionDAG.h"
|
2010-02-16 06:37:53 +08:00
|
|
|
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
|
2008-10-11 04:28:10 +08:00
|
|
|
#include "llvm/ADT/VectorExtras.h"
|
2009-07-12 04:10:48 +08:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2008-03-17 11:21:36 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
2008-03-17 13:41:48 +08:00
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2008-03-17 13:41:48 +08:00
|
|
|
// Calling Convention Implementation
|
2008-03-17 11:21:36 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2011-01-22 21:05:16 +08:00
|
|
|
static bool CC_Sparc_Assign_SRet(unsigned &ValNo, MVT &ValVT,
|
|
|
|
MVT &LocVT, CCValAssign::LocInfo &LocInfo,
|
|
|
|
ISD::ArgFlagsTy &ArgFlags, CCState &State)
|
|
|
|
{
|
|
|
|
assert (ArgFlags.isSRet());
|
|
|
|
|
|
|
|
//Assign SRet argument
|
|
|
|
State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT,
|
|
|
|
0,
|
|
|
|
LocVT, LocInfo));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-01-18 14:09:55 +08:00
|
|
|
static bool CC_Sparc_Assign_f64(unsigned &ValNo, MVT &ValVT,
|
|
|
|
MVT &LocVT, CCValAssign::LocInfo &LocInfo,
|
|
|
|
ISD::ArgFlagsTy &ArgFlags, CCState &State)
|
|
|
|
{
|
|
|
|
static const unsigned RegList[] = {
|
|
|
|
SP::I0, SP::I1, SP::I2, SP::I3, SP::I4, SP::I5
|
|
|
|
};
|
|
|
|
//Try to get first reg
|
|
|
|
if (unsigned Reg = State.AllocateReg(RegList, 6)) {
|
|
|
|
State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
|
|
|
|
} else {
|
|
|
|
//Assign whole thing in stack
|
|
|
|
State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT,
|
|
|
|
State.AllocateStack(8,4),
|
|
|
|
LocVT, LocInfo));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Try to get second reg
|
|
|
|
if (unsigned Reg = State.AllocateReg(RegList, 6))
|
|
|
|
State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
|
|
|
|
else
|
|
|
|
State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT,
|
|
|
|
State.AllocateStack(4,4),
|
|
|
|
LocVT, LocInfo));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-03-17 13:41:48 +08:00
|
|
|
#include "SparcGenCallingConv.inc"
|
2008-03-17 11:21:36 +08:00
|
|
|
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
SDValue
|
|
|
|
SparcTargetLowering::LowerReturn(SDValue Chain,
|
2009-09-02 16:44:58 +08:00
|
|
|
CallingConv::ID CallConv, bool isVarArg,
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
2010-07-07 23:54:55 +08:00
|
|
|
const SmallVectorImpl<SDValue> &OutVals,
|
2010-04-17 23:26:15 +08:00
|
|
|
DebugLoc dl, SelectionDAG &DAG) const {
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
|
2011-01-22 21:05:16 +08:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
|
2008-03-17 13:41:48 +08:00
|
|
|
// CCValAssign - represent the assignment of the return value to locations.
|
|
|
|
SmallVector<CCValAssign, 16> RVLocs;
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 13:41:48 +08:00
|
|
|
// CCState - Info about the registers and stack slot.
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
CCState CCInfo(CallConv, isVarArg, DAG.getTarget(),
|
|
|
|
RVLocs, *DAG.getContext());
|
2008-10-11 04:27:31 +08:00
|
|
|
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
// Analize return values.
|
|
|
|
CCInfo.AnalyzeReturn(Outs, RetCC_Sparc32);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 13:41:48 +08:00
|
|
|
// If this is the first return lowered for this function, add the regs to the
|
|
|
|
// liveout set for the function.
|
2011-01-22 21:05:16 +08:00
|
|
|
if (MF.getRegInfo().liveout_empty()) {
|
2008-03-17 13:41:48 +08:00
|
|
|
for (unsigned i = 0; i != RVLocs.size(); ++i)
|
|
|
|
if (RVLocs[i].isRegLoc())
|
2011-01-22 21:05:16 +08:00
|
|
|
MF.getRegInfo().addLiveOut(RVLocs[i].getLocReg());
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-07-28 05:46:04 +08:00
|
|
|
SDValue Flag;
|
2008-03-17 11:21:36 +08:00
|
|
|
|
2008-03-17 13:41:48 +08:00
|
|
|
// Copy the result values into the output registers.
|
|
|
|
for (unsigned i = 0; i != RVLocs.size(); ++i) {
|
|
|
|
CCValAssign &VA = RVLocs[i];
|
|
|
|
assert(VA.isRegLoc() && "Can only return in registers!");
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2010-11-23 11:31:01 +08:00
|
|
|
Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(),
|
2010-07-07 23:54:55 +08:00
|
|
|
OutVals[i], Flag);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 13:41:48 +08:00
|
|
|
// Guarantee that all emitted copies are stuck together with flags.
|
|
|
|
Flag = Chain.getValue(1);
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
2011-02-21 11:42:44 +08:00
|
|
|
|
|
|
|
unsigned RetAddrOffset = 8; //Call Inst + Delay Slot
|
2011-01-22 21:05:16 +08:00
|
|
|
// If the function returns a struct, copy the SRetReturnReg to I0
|
|
|
|
if (MF.getFunction()->hasStructRetAttr()) {
|
|
|
|
SparcMachineFunctionInfo *SFI = MF.getInfo<SparcMachineFunctionInfo>();
|
|
|
|
unsigned Reg = SFI->getSRetReturnReg();
|
|
|
|
if (!Reg)
|
|
|
|
llvm_unreachable("sret virtual register not created in the entry block");
|
|
|
|
SDValue Val = DAG.getCopyFromReg(Chain, dl, Reg, getPointerTy());
|
|
|
|
Chain = DAG.getCopyToReg(Chain, dl, SP::I0, Val, Flag);
|
|
|
|
Flag = Chain.getValue(1);
|
|
|
|
if (MF.getRegInfo().liveout_empty())
|
|
|
|
MF.getRegInfo().addLiveOut(SP::I0);
|
2011-02-21 11:42:44 +08:00
|
|
|
RetAddrOffset = 12; // CallInst + Delay Slot + Unimp
|
2011-01-22 21:05:16 +08:00
|
|
|
}
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2011-02-21 11:42:44 +08:00
|
|
|
SDValue RetAddrOffsetNode = DAG.getConstant(RetAddrOffset, MVT::i32);
|
|
|
|
|
2008-08-29 05:40:38 +08:00
|
|
|
if (Flag.getNode())
|
2011-02-21 11:42:44 +08:00
|
|
|
return DAG.getNode(SPISD::RET_FLAG, dl, MVT::Other, Chain,
|
|
|
|
RetAddrOffsetNode, Flag);
|
|
|
|
return DAG.getNode(SPISD::RET_FLAG, dl, MVT::Other, Chain,
|
|
|
|
RetAddrOffsetNode);
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
|
|
|
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
/// LowerFormalArguments - V8 uses a very simple ABI, where all values are
|
|
|
|
/// passed in either one or two GPRs, including FP values. TODO: we should
|
|
|
|
/// pass FP values in FP registers for fastcc functions.
|
2009-07-20 03:53:46 +08:00
|
|
|
SDValue
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
SparcTargetLowering::LowerFormalArguments(SDValue Chain,
|
2009-09-02 16:44:58 +08:00
|
|
|
CallingConv::ID CallConv, bool isVarArg,
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
const SmallVectorImpl<ISD::InputArg>
|
|
|
|
&Ins,
|
|
|
|
DebugLoc dl, SelectionDAG &DAG,
|
2010-04-17 23:26:15 +08:00
|
|
|
SmallVectorImpl<SDValue> &InVals)
|
|
|
|
const {
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
MachineRegisterInfo &RegInfo = MF.getRegInfo();
|
2010-04-17 22:41:14 +08:00
|
|
|
SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
|
2009-07-20 03:53:46 +08:00
|
|
|
|
|
|
|
// Assign locations to all of the incoming arguments.
|
|
|
|
SmallVector<CCValAssign, 16> ArgLocs;
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
CCState CCInfo(CallConv, isVarArg, getTargetMachine(),
|
|
|
|
ArgLocs, *DAG.getContext());
|
|
|
|
CCInfo.AnalyzeFormalArguments(Ins, CC_Sparc32);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2011-01-18 14:09:55 +08:00
|
|
|
const unsigned StackOffset = 92;
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2009-07-20 03:53:46 +08:00
|
|
|
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
|
|
|
CCValAssign &VA = ArgLocs[i];
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2011-01-22 21:05:16 +08:00
|
|
|
if (i == 0 && Ins[i].Flags.isSRet()) {
|
|
|
|
//Get SRet from [%fp+64]
|
|
|
|
int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, 64, true);
|
|
|
|
SDValue FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32);
|
|
|
|
SDValue Arg = DAG.getLoad(MVT::i32, dl, Chain, FIPtr,
|
|
|
|
MachinePointerInfo(),
|
|
|
|
false, false, 0);
|
|
|
|
InVals.push_back(Arg);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-01-18 14:09:55 +08:00
|
|
|
if (VA.isRegLoc()) {
|
|
|
|
if (VA.needsCustom()) {
|
|
|
|
assert(VA.getLocVT() == MVT::f64);
|
|
|
|
unsigned VRegHi = RegInfo.createVirtualRegister(&SP::IntRegsRegClass);
|
|
|
|
MF.getRegInfo().addLiveIn(VA.getLocReg(), VRegHi);
|
|
|
|
SDValue HiVal = DAG.getCopyFromReg(Chain, dl, VRegHi, MVT::i32);
|
2008-03-17 11:21:36 +08:00
|
|
|
|
2011-01-18 14:09:55 +08:00
|
|
|
assert(i+1 < e);
|
|
|
|
CCValAssign &NextVA = ArgLocs[++i];
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-07-28 05:46:04 +08:00
|
|
|
SDValue LoVal;
|
2011-01-18 14:09:55 +08:00
|
|
|
if (NextVA.isMemLoc()) {
|
|
|
|
int FrameIdx = MF.getFrameInfo()->
|
|
|
|
CreateFixedObject(4, StackOffset+NextVA.getLocMemOffset(),true);
|
2009-08-12 04:47:22 +08:00
|
|
|
SDValue FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32);
|
2011-01-18 14:09:55 +08:00
|
|
|
LoVal = DAG.getLoad(MVT::i32, dl, Chain, FIPtr,
|
|
|
|
MachinePointerInfo(),
|
2010-02-16 00:57:02 +08:00
|
|
|
false, false, 0);
|
2011-01-18 14:09:55 +08:00
|
|
|
} else {
|
|
|
|
unsigned loReg = MF.addLiveIn(NextVA.getLocReg(),
|
2011-02-22 07:21:26 +08:00
|
|
|
&SP::IntRegsRegClass);
|
2011-01-18 14:09:55 +08:00
|
|
|
LoVal = DAG.getCopyFromReg(Chain, dl, loReg, MVT::i32);
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
2008-10-11 04:27:31 +08:00
|
|
|
SDValue WholeValue =
|
2009-08-12 04:47:22 +08:00
|
|
|
DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, LoVal, HiVal);
|
2011-01-18 14:09:55 +08:00
|
|
|
WholeValue = DAG.getNode(ISD::BITCAST, dl, MVT::f64, WholeValue);
|
|
|
|
InVals.push_back(WholeValue);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
unsigned VReg = RegInfo.createVirtualRegister(&SP::IntRegsRegClass);
|
|
|
|
MF.getRegInfo().addLiveIn(VA.getLocReg(), VReg);
|
|
|
|
SDValue Arg = DAG.getCopyFromReg(Chain, dl, VReg, MVT::i32);
|
|
|
|
if (VA.getLocVT() == MVT::f32)
|
|
|
|
Arg = DAG.getNode(ISD::BITCAST, dl, MVT::f32, Arg);
|
|
|
|
else if (VA.getLocVT() != MVT::i32) {
|
|
|
|
Arg = DAG.getNode(ISD::AssertSext, dl, MVT::i32, Arg,
|
|
|
|
DAG.getValueType(VA.getLocVT()));
|
|
|
|
Arg = DAG.getNode(ISD::TRUNCATE, dl, VA.getLocVT(), Arg);
|
|
|
|
}
|
|
|
|
InVals.push_back(Arg);
|
|
|
|
continue;
|
|
|
|
}
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2011-01-18 14:09:55 +08:00
|
|
|
assert(VA.isMemLoc());
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2011-01-18 14:09:55 +08:00
|
|
|
unsigned Offset = VA.getLocMemOffset()+StackOffset;
|
|
|
|
|
|
|
|
if (VA.needsCustom()) {
|
|
|
|
assert(VA.getValVT() == MVT::f64);
|
|
|
|
//If it is double-word aligned, just load.
|
|
|
|
if (Offset % 8 == 0) {
|
|
|
|
int FI = MF.getFrameInfo()->CreateFixedObject(8,
|
|
|
|
Offset,
|
|
|
|
true);
|
|
|
|
SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy());
|
|
|
|
SDValue Load = DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr,
|
|
|
|
MachinePointerInfo(),
|
|
|
|
false,false, 0);
|
|
|
|
InVals.push_back(Load);
|
|
|
|
continue;
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
2011-01-18 14:09:55 +08:00
|
|
|
|
|
|
|
int FI = MF.getFrameInfo()->CreateFixedObject(4,
|
|
|
|
Offset,
|
|
|
|
true);
|
|
|
|
SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy());
|
|
|
|
SDValue HiVal = DAG.getLoad(MVT::i32, dl, Chain, FIPtr,
|
|
|
|
MachinePointerInfo(),
|
|
|
|
false, false, 0);
|
|
|
|
int FI2 = MF.getFrameInfo()->CreateFixedObject(4,
|
|
|
|
Offset+4,
|
|
|
|
true);
|
|
|
|
SDValue FIPtr2 = DAG.getFrameIndex(FI2, getPointerTy());
|
|
|
|
|
|
|
|
SDValue LoVal = DAG.getLoad(MVT::i32, dl, Chain, FIPtr2,
|
|
|
|
MachinePointerInfo(),
|
|
|
|
false, false, 0);
|
|
|
|
|
|
|
|
SDValue WholeValue =
|
|
|
|
DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, LoVal, HiVal);
|
|
|
|
WholeValue = DAG.getNode(ISD::BITCAST, dl, MVT::f64, WholeValue);
|
|
|
|
InVals.push_back(WholeValue);
|
|
|
|
continue;
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
2011-01-18 14:09:55 +08:00
|
|
|
|
|
|
|
int FI = MF.getFrameInfo()->CreateFixedObject(4,
|
|
|
|
Offset,
|
|
|
|
true);
|
|
|
|
SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy());
|
|
|
|
SDValue Load ;
|
|
|
|
if (VA.getValVT() == MVT::i32 || VA.getValVT() == MVT::f32) {
|
|
|
|
Load = DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr,
|
|
|
|
MachinePointerInfo(),
|
|
|
|
false, false, 0);
|
|
|
|
} else {
|
|
|
|
ISD::LoadExtType LoadOp = ISD::SEXTLOAD;
|
|
|
|
// Sparc is big endian, so add an offset based on the ObjectVT.
|
|
|
|
unsigned Offset = 4-std::max(1U, VA.getValVT().getSizeInBits()/8);
|
|
|
|
FIPtr = DAG.getNode(ISD::ADD, dl, MVT::i32, FIPtr,
|
|
|
|
DAG.getConstant(Offset, MVT::i32));
|
2011-02-17 00:23:55 +08:00
|
|
|
Load = DAG.getExtLoad(LoadOp, dl, MVT::i32, Chain, FIPtr,
|
2011-01-18 14:09:55 +08:00
|
|
|
MachinePointerInfo(),
|
|
|
|
VA.getValVT(), false, false,0);
|
|
|
|
Load = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), Load);
|
|
|
|
}
|
|
|
|
InVals.push_back(Load);
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2011-01-22 21:05:16 +08:00
|
|
|
if (MF.getFunction()->hasStructRetAttr()) {
|
|
|
|
//Copy the SRet Argument to SRetReturnReg
|
|
|
|
SparcMachineFunctionInfo *SFI = MF.getInfo<SparcMachineFunctionInfo>();
|
|
|
|
unsigned Reg = SFI->getSRetReturnReg();
|
|
|
|
if (!Reg) {
|
|
|
|
Reg = MF.getRegInfo().createVirtualRegister(&SP::IntRegsRegClass);
|
|
|
|
SFI->setSRetReturnReg(Reg);
|
|
|
|
}
|
|
|
|
SDValue Copy = DAG.getCopyToReg(DAG.getEntryNode(), dl, Reg, InVals[0]);
|
|
|
|
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Copy, Chain);
|
|
|
|
}
|
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
// Store remaining ArgRegs to the stack if this is a varargs function.
|
2009-07-20 03:53:46 +08:00
|
|
|
if (isVarArg) {
|
2011-01-18 14:09:55 +08:00
|
|
|
static const unsigned ArgRegs[] = {
|
|
|
|
SP::I0, SP::I1, SP::I2, SP::I3, SP::I4, SP::I5
|
|
|
|
};
|
|
|
|
unsigned NumAllocated = CCInfo.getFirstUnallocated(ArgRegs, 6);
|
|
|
|
const unsigned *CurArgReg = ArgRegs+NumAllocated, *ArgRegEnd = ArgRegs+6;
|
|
|
|
unsigned ArgOffset = CCInfo.getNextStackOffset();
|
|
|
|
if (NumAllocated == 6)
|
|
|
|
ArgOffset += StackOffset;
|
|
|
|
else {
|
|
|
|
assert(!ArgOffset);
|
|
|
|
ArgOffset = 68+4*NumAllocated;
|
|
|
|
}
|
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
// Remember the vararg offset for the va_start implementation.
|
2010-04-17 22:41:14 +08:00
|
|
|
FuncInfo->setVarArgsFrameOffset(ArgOffset);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2009-07-20 03:53:46 +08:00
|
|
|
std::vector<SDValue> OutChains;
|
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
for (; CurArgReg != ArgRegEnd; ++CurArgReg) {
|
|
|
|
unsigned VReg = RegInfo.createVirtualRegister(&SP::IntRegsRegClass);
|
|
|
|
MF.getRegInfo().addLiveIn(*CurArgReg, VReg);
|
2009-08-12 04:47:22 +08:00
|
|
|
SDValue Arg = DAG.getCopyFromReg(DAG.getRoot(), dl, VReg, MVT::i32);
|
2008-03-17 11:21:36 +08:00
|
|
|
|
2009-11-13 04:49:22 +08:00
|
|
|
int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, ArgOffset,
|
2010-07-03 08:40:23 +08:00
|
|
|
true);
|
2009-08-12 04:47:22 +08:00
|
|
|
SDValue FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32);
|
2008-03-17 11:21:36 +08:00
|
|
|
|
2010-09-22 02:41:36 +08:00
|
|
|
OutChains.push_back(DAG.getStore(DAG.getRoot(), dl, Arg, FIPtr,
|
|
|
|
MachinePointerInfo(),
|
2010-02-16 00:57:02 +08:00
|
|
|
false, false, 0));
|
2008-03-17 11:21:36 +08:00
|
|
|
ArgOffset += 4;
|
|
|
|
}
|
2009-07-20 03:53:46 +08:00
|
|
|
|
|
|
|
if (!OutChains.empty()) {
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
OutChains.push_back(Chain);
|
2009-08-12 04:47:22 +08:00
|
|
|
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
&OutChains[0], OutChains.size());
|
2009-07-20 03:53:46 +08:00
|
|
|
}
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
2008-10-11 04:27:31 +08:00
|
|
|
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
return Chain;
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
|
|
|
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
SDValue
|
2010-02-03 07:55:14 +08:00
|
|
|
SparcTargetLowering::LowerCall(SDValue Chain, SDValue Callee,
|
2009-09-02 16:44:58 +08:00
|
|
|
CallingConv::ID CallConv, bool isVarArg,
|
2010-01-27 08:07:07 +08:00
|
|
|
bool &isTailCall,
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
2010-07-07 23:54:55 +08:00
|
|
|
const SmallVectorImpl<SDValue> &OutVals,
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
const SmallVectorImpl<ISD::InputArg> &Ins,
|
|
|
|
DebugLoc dl, SelectionDAG &DAG,
|
2010-04-17 23:26:15 +08:00
|
|
|
SmallVectorImpl<SDValue> &InVals) const {
|
2010-01-27 08:07:07 +08:00
|
|
|
// Sparc target does not yet support tail call optimization.
|
|
|
|
isTailCall = false;
|
2008-03-17 14:01:07 +08:00
|
|
|
|
2008-03-17 14:58:37 +08:00
|
|
|
// Analyze operands of the call, assigning locations to each operand.
|
|
|
|
SmallVector<CCValAssign, 16> ArgLocs;
|
2011-01-18 14:09:55 +08:00
|
|
|
CCState CCInfo(CallConv, isVarArg, DAG.getTarget(), ArgLocs,
|
|
|
|
*DAG.getContext());
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
CCInfo.AnalyzeCallOperands(Outs, CC_Sparc32);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 14:58:37 +08:00
|
|
|
// Get the size of the outgoing arguments stack space requirement.
|
|
|
|
unsigned ArgsSize = CCInfo.getNextStackOffset();
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
// Keep stack frames 8-byte aligned.
|
|
|
|
ArgsSize = (ArgsSize+7) & ~7;
|
|
|
|
|
2011-01-21 22:00:01 +08:00
|
|
|
MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
|
|
|
|
|
|
|
|
//Create local copies for byval args.
|
|
|
|
SmallVector<SDValue, 8> ByValArgs;
|
|
|
|
for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
|
|
|
|
ISD::ArgFlagsTy Flags = Outs[i].Flags;
|
|
|
|
if (!Flags.isByVal())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
SDValue Arg = OutVals[i];
|
|
|
|
unsigned Size = Flags.getByValSize();
|
|
|
|
unsigned Align = Flags.getByValAlign();
|
|
|
|
|
|
|
|
int FI = MFI->CreateStackObject(Size, Align, false);
|
|
|
|
SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy());
|
|
|
|
SDValue SizeNode = DAG.getConstant(Size, MVT::i32);
|
|
|
|
|
|
|
|
Chain = DAG.getMemcpy(Chain, dl, FIPtr, Arg, SizeNode, Align,
|
|
|
|
false, //isVolatile,
|
|
|
|
(Size <= 32), //AlwaysInline if size <= 32
|
|
|
|
MachinePointerInfo(), MachinePointerInfo());
|
|
|
|
ByValArgs.push_back(FIPtr);
|
|
|
|
}
|
|
|
|
|
2008-10-12 06:08:30 +08:00
|
|
|
Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(ArgsSize, true));
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-07-28 05:46:04 +08:00
|
|
|
SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass;
|
|
|
|
SmallVector<SDValue, 8> MemOpChains;
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2011-01-18 14:09:55 +08:00
|
|
|
const unsigned StackOffset = 92;
|
2011-02-21 11:42:44 +08:00
|
|
|
bool hasStructRetAttr = false;
|
2008-03-17 14:58:37 +08:00
|
|
|
// Walk the register/memloc assignments, inserting copies/loads.
|
2011-01-21 22:00:01 +08:00
|
|
|
for (unsigned i = 0, realArgIdx = 0, byvalArgIdx = 0, e = ArgLocs.size();
|
2011-01-18 14:09:55 +08:00
|
|
|
i != e;
|
|
|
|
++i, ++realArgIdx) {
|
2008-03-17 14:58:37 +08:00
|
|
|
CCValAssign &VA = ArgLocs[i];
|
2011-01-18 14:09:55 +08:00
|
|
|
SDValue Arg = OutVals[realArgIdx];
|
2008-03-17 14:58:37 +08:00
|
|
|
|
2011-01-21 22:00:01 +08:00
|
|
|
ISD::ArgFlagsTy Flags = Outs[realArgIdx].Flags;
|
|
|
|
|
|
|
|
//Use local copy if it is a byval arg.
|
|
|
|
if (Flags.isByVal())
|
|
|
|
Arg = ByValArgs[byvalArgIdx++];
|
|
|
|
|
2008-03-17 14:58:37 +08:00
|
|
|
// Promote the value if needed.
|
|
|
|
switch (VA.getLocInfo()) {
|
2009-07-15 00:55:14 +08:00
|
|
|
default: llvm_unreachable("Unknown loc info!");
|
2008-03-17 14:58:37 +08:00
|
|
|
case CCValAssign::Full: break;
|
|
|
|
case CCValAssign::SExt:
|
2011-01-18 14:09:55 +08:00
|
|
|
Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg);
|
2008-03-17 14:58:37 +08:00
|
|
|
break;
|
|
|
|
case CCValAssign::ZExt:
|
2011-01-18 14:09:55 +08:00
|
|
|
Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg);
|
2008-03-17 14:58:37 +08:00
|
|
|
break;
|
|
|
|
case CCValAssign::AExt:
|
2011-01-18 14:09:55 +08:00
|
|
|
Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg);
|
|
|
|
break;
|
|
|
|
case CCValAssign::BCvt:
|
|
|
|
Arg = DAG.getNode(ISD::BITCAST, dl, VA.getLocVT(), Arg);
|
2008-03-17 14:58:37 +08:00
|
|
|
break;
|
|
|
|
}
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2011-01-22 21:05:16 +08:00
|
|
|
if (Flags.isSRet()) {
|
|
|
|
assert(VA.needsCustom());
|
|
|
|
// store SRet argument in %sp+64
|
|
|
|
SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32);
|
|
|
|
SDValue PtrOff = DAG.getIntPtrConstant(64);
|
|
|
|
PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff);
|
|
|
|
MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff,
|
|
|
|
MachinePointerInfo(),
|
|
|
|
false, false, 0));
|
2011-02-21 11:42:44 +08:00
|
|
|
hasStructRetAttr = true;
|
2011-01-22 21:05:16 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-01-18 14:09:55 +08:00
|
|
|
if (VA.needsCustom()) {
|
|
|
|
assert(VA.getLocVT() == MVT::f64);
|
|
|
|
|
|
|
|
if (VA.isMemLoc()) {
|
|
|
|
unsigned Offset = VA.getLocMemOffset() + StackOffset;
|
|
|
|
//if it is double-word aligned, just store.
|
|
|
|
if (Offset % 8 == 0) {
|
|
|
|
SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32);
|
|
|
|
SDValue PtrOff = DAG.getIntPtrConstant(Offset);
|
|
|
|
PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff);
|
|
|
|
MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff,
|
|
|
|
MachinePointerInfo(),
|
|
|
|
false, false, 0));
|
|
|
|
continue;
|
2010-12-29 13:37:15 +08:00
|
|
|
}
|
2008-12-12 16:05:40 +08:00
|
|
|
}
|
2011-01-18 14:09:55 +08:00
|
|
|
|
2009-08-12 04:47:22 +08:00
|
|
|
SDValue StackPtr = DAG.CreateStackTemporary(MVT::f64, MVT::i32);
|
2010-11-23 11:31:01 +08:00
|
|
|
SDValue Store = DAG.getStore(DAG.getEntryNode(), dl,
|
2011-01-18 14:09:55 +08:00
|
|
|
Arg, StackPtr, MachinePointerInfo(),
|
2010-02-16 00:57:02 +08:00
|
|
|
false, false, 0);
|
2008-12-12 16:05:40 +08:00
|
|
|
// Sparc is big-endian, so the high part comes first.
|
2010-09-21 14:44:06 +08:00
|
|
|
SDValue Hi = DAG.getLoad(MVT::i32, dl, Store, StackPtr,
|
|
|
|
MachinePointerInfo(), false, false, 0);
|
2008-12-12 16:05:40 +08:00
|
|
|
// Increment the pointer to the other half.
|
2009-02-05 04:06:27 +08:00
|
|
|
StackPtr = DAG.getNode(ISD::ADD, dl, StackPtr.getValueType(), StackPtr,
|
2008-12-12 16:05:40 +08:00
|
|
|
DAG.getIntPtrConstant(4));
|
|
|
|
// Load the low part.
|
2010-09-21 14:44:06 +08:00
|
|
|
SDValue Lo = DAG.getLoad(MVT::i32, dl, Store, StackPtr,
|
|
|
|
MachinePointerInfo(), false, false, 0);
|
2008-12-12 16:05:40 +08:00
|
|
|
|
2011-01-18 14:09:55 +08:00
|
|
|
if (VA.isRegLoc()) {
|
|
|
|
RegsToPass.push_back(std::make_pair(VA.getLocReg(), Hi));
|
|
|
|
assert(i+1 != e);
|
|
|
|
CCValAssign &NextVA = ArgLocs[++i];
|
|
|
|
if (NextVA.isRegLoc()) {
|
|
|
|
RegsToPass.push_back(std::make_pair(NextVA.getLocReg(), Lo));
|
|
|
|
} else {
|
|
|
|
//Store the low part in stack.
|
|
|
|
unsigned Offset = NextVA.getLocMemOffset() + StackOffset;
|
|
|
|
SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32);
|
|
|
|
SDValue PtrOff = DAG.getIntPtrConstant(Offset);
|
|
|
|
PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff);
|
|
|
|
MemOpChains.push_back(DAG.getStore(Chain, dl, Lo, PtrOff,
|
|
|
|
MachinePointerInfo(),
|
|
|
|
false, false, 0));
|
|
|
|
}
|
2008-12-12 16:05:40 +08:00
|
|
|
} else {
|
2011-01-18 14:09:55 +08:00
|
|
|
unsigned Offset = VA.getLocMemOffset() + StackOffset;
|
|
|
|
// Store the high part.
|
|
|
|
SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32);
|
|
|
|
SDValue PtrOff = DAG.getIntPtrConstant(Offset);
|
|
|
|
PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff);
|
|
|
|
MemOpChains.push_back(DAG.getStore(Chain, dl, Hi, PtrOff,
|
|
|
|
MachinePointerInfo(),
|
|
|
|
false, false, 0));
|
|
|
|
// Store the low part.
|
|
|
|
PtrOff = DAG.getIntPtrConstant(Offset+4);
|
|
|
|
PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff);
|
|
|
|
MemOpChains.push_back(DAG.getStore(Chain, dl, Lo, PtrOff,
|
|
|
|
MachinePointerInfo(),
|
|
|
|
false, false, 0));
|
2008-12-12 16:05:40 +08:00
|
|
|
}
|
2011-01-18 14:09:55 +08:00
|
|
|
continue;
|
2008-12-12 16:05:40 +08:00
|
|
|
}
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2011-01-18 14:09:55 +08:00
|
|
|
// Arguments that can be passed on register must be kept at
|
|
|
|
// RegsToPass vector
|
|
|
|
if (VA.isRegLoc()) {
|
|
|
|
if (VA.getLocVT() != MVT::f32) {
|
|
|
|
RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
|
|
|
|
continue;
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
2011-01-18 14:09:55 +08:00
|
|
|
Arg = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Arg);
|
|
|
|
RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
|
|
|
|
continue;
|
2008-12-12 16:05:40 +08:00
|
|
|
}
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2011-01-18 14:09:55 +08:00
|
|
|
assert(VA.isMemLoc());
|
|
|
|
|
|
|
|
// Create a store off the stack pointer for this argument.
|
|
|
|
SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32);
|
|
|
|
SDValue PtrOff = DAG.getIntPtrConstant(VA.getLocMemOffset()+StackOffset);
|
|
|
|
PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff);
|
|
|
|
MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff,
|
|
|
|
MachinePointerInfo(),
|
|
|
|
false, false, 0));
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
2011-01-18 14:09:55 +08:00
|
|
|
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
// Emit all stores, make sure the occur before any copies into physregs.
|
2008-03-17 14:58:37 +08:00
|
|
|
if (!MemOpChains.empty())
|
2009-08-12 04:47:22 +08:00
|
|
|
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
|
2008-03-17 14:58:37 +08:00
|
|
|
&MemOpChains[0], MemOpChains.size());
|
2008-10-11 04:27:31 +08:00
|
|
|
|
|
|
|
// Build a sequence of copy-to-reg nodes chained together with token
|
2008-03-17 14:58:37 +08:00
|
|
|
// chain and flag operands which copy the outgoing args into registers.
|
2011-04-15 13:18:47 +08:00
|
|
|
// The InFlag in necessary since all emitted instructions must be
|
2008-03-17 14:58:37 +08:00
|
|
|
// stuck together.
|
2008-07-28 05:46:04 +08:00
|
|
|
SDValue InFlag;
|
2008-03-17 14:58:37 +08:00
|
|
|
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
|
|
|
|
unsigned Reg = RegsToPass[i].first;
|
|
|
|
// Remap I0->I7 -> O0->O7.
|
|
|
|
if (Reg >= SP::I0 && Reg <= SP::I7)
|
|
|
|
Reg = Reg-SP::I0+SP::O0;
|
|
|
|
|
2009-02-05 04:06:27 +08:00
|
|
|
Chain = DAG.getCopyToReg(Chain, dl, Reg, RegsToPass[i].second, InFlag);
|
2008-03-17 11:21:36 +08:00
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
}
|
|
|
|
|
2011-02-21 11:42:44 +08:00
|
|
|
unsigned SRetArgSize = (hasStructRetAttr)? getSRetArgSize(DAG, Callee):0;
|
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
// If the callee is a GlobalAddress node (quite common, every direct call is)
|
|
|
|
// turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
|
2008-09-17 05:48:12 +08:00
|
|
|
// Likewise ExternalSymbol -> TargetExternalSymbol.
|
2008-03-17 11:21:36 +08:00
|
|
|
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
|
2010-07-07 06:08:15 +08:00
|
|
|
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i32);
|
2008-09-17 05:48:12 +08:00
|
|
|
else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee))
|
2009-08-12 04:47:22 +08:00
|
|
|
Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32);
|
2008-03-17 11:21:36 +08:00
|
|
|
|
2011-01-12 11:18:21 +08:00
|
|
|
// Returns a chain & a flag for retval copy to use
|
|
|
|
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
|
|
|
|
SmallVector<SDValue, 8> Ops;
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(Callee);
|
2011-02-21 11:42:44 +08:00
|
|
|
if (hasStructRetAttr)
|
|
|
|
Ops.push_back(DAG.getTargetConstant(SRetArgSize, MVT::i32));
|
2011-01-12 11:18:21 +08:00
|
|
|
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
|
|
|
|
unsigned Reg = RegsToPass[i].first;
|
|
|
|
if (Reg >= SP::I0 && Reg <= SP::I7)
|
|
|
|
Reg = Reg-SP::I0+SP::O0;
|
|
|
|
|
|
|
|
Ops.push_back(DAG.getRegister(Reg, RegsToPass[i].second.getValueType()));
|
|
|
|
}
|
|
|
|
if (InFlag.getNode())
|
|
|
|
Ops.push_back(InFlag);
|
|
|
|
|
|
|
|
Chain = DAG.getNode(SPISD::CALL, dl, NodeTys, &Ops[0], Ops.size());
|
2008-03-17 11:21:36 +08:00
|
|
|
InFlag = Chain.getValue(1);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-10-12 06:08:30 +08:00
|
|
|
Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(ArgsSize, true),
|
|
|
|
DAG.getIntPtrConstant(0, true), InFlag);
|
2008-03-17 14:01:07 +08:00
|
|
|
InFlag = Chain.getValue(1);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 14:01:07 +08:00
|
|
|
// Assign locations to each value returned by this call.
|
|
|
|
SmallVector<CCValAssign, 16> RVLocs;
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
CCState RVInfo(CallConv, isVarArg, DAG.getTarget(),
|
2009-07-22 08:24:57 +08:00
|
|
|
RVLocs, *DAG.getContext());
|
2008-10-11 04:27:31 +08:00
|
|
|
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
RVInfo.AnalyzeCallResult(Ins, RetCC_Sparc32);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 14:01:07 +08:00
|
|
|
// Copy all of the result registers out of their specified physreg.
|
|
|
|
for (unsigned i = 0; i != RVLocs.size(); ++i) {
|
|
|
|
unsigned Reg = RVLocs[i].getLocReg();
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 14:01:07 +08:00
|
|
|
// Remap I0->I7 -> O0->O7.
|
|
|
|
if (Reg >= SP::I0 && Reg <= SP::I7)
|
|
|
|
Reg = Reg-SP::I0+SP::O0;
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2009-02-05 04:06:27 +08:00
|
|
|
Chain = DAG.getCopyFromReg(Chain, dl, Reg,
|
2008-03-17 14:01:07 +08:00
|
|
|
RVLocs[i].getValVT(), InFlag).getValue(1);
|
|
|
|
InFlag = Chain.getValue(2);
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
InVals.push_back(Chain.getValue(0));
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
2008-10-11 04:27:31 +08:00
|
|
|
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
return Chain;
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
|
|
|
|
2011-02-21 11:42:44 +08:00
|
|
|
unsigned
|
|
|
|
SparcTargetLowering::getSRetArgSize(SelectionDAG &DAG, SDValue Callee) const
|
|
|
|
{
|
|
|
|
const Function *CalleeFn = 0;
|
|
|
|
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
|
|
|
|
CalleeFn = dyn_cast<Function>(G->getGlobal());
|
|
|
|
} else if (ExternalSymbolSDNode *E =
|
|
|
|
dyn_cast<ExternalSymbolSDNode>(Callee)) {
|
|
|
|
const Function *Fn = DAG.getMachineFunction().getFunction();
|
|
|
|
const Module *M = Fn->getParent();
|
|
|
|
CalleeFn = M->getFunction(E->getSymbol());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CalleeFn)
|
|
|
|
return 0;
|
2008-03-17 13:41:48 +08:00
|
|
|
|
2011-02-21 11:42:44 +08:00
|
|
|
assert(CalleeFn->hasStructRetAttr() &&
|
|
|
|
"Callee does not have the StructRet attribute.");
|
|
|
|
|
|
|
|
const PointerType *Ty = cast<PointerType>(CalleeFn->arg_begin()->getType());
|
|
|
|
const Type *ElementTy = Ty->getElementType();
|
|
|
|
return getTargetData()->getTypeAllocSize(ElementTy);
|
|
|
|
}
|
2008-03-17 13:41:48 +08:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// TargetLowering Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
/// IntCondCCodeToICC - Convert a DAG integer condition code to a SPARC ICC
|
|
|
|
/// condition.
|
|
|
|
static SPCC::CondCodes IntCondCCodeToICC(ISD::CondCode CC) {
|
|
|
|
switch (CC) {
|
2009-07-15 00:55:14 +08:00
|
|
|
default: llvm_unreachable("Unknown integer condition code!");
|
2008-03-17 13:41:48 +08:00
|
|
|
case ISD::SETEQ: return SPCC::ICC_E;
|
|
|
|
case ISD::SETNE: return SPCC::ICC_NE;
|
|
|
|
case ISD::SETLT: return SPCC::ICC_L;
|
|
|
|
case ISD::SETGT: return SPCC::ICC_G;
|
|
|
|
case ISD::SETLE: return SPCC::ICC_LE;
|
|
|
|
case ISD::SETGE: return SPCC::ICC_GE;
|
|
|
|
case ISD::SETULT: return SPCC::ICC_CS;
|
|
|
|
case ISD::SETULE: return SPCC::ICC_LEU;
|
|
|
|
case ISD::SETUGT: return SPCC::ICC_GU;
|
|
|
|
case ISD::SETUGE: return SPCC::ICC_CC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// FPCondCCodeToFCC - Convert a DAG floatingp oint condition code to a SPARC
|
|
|
|
/// FCC condition.
|
|
|
|
static SPCC::CondCodes FPCondCCodeToFCC(ISD::CondCode CC) {
|
|
|
|
switch (CC) {
|
2009-07-15 00:55:14 +08:00
|
|
|
default: llvm_unreachable("Unknown fp condition code!");
|
2008-03-17 13:41:48 +08:00
|
|
|
case ISD::SETEQ:
|
|
|
|
case ISD::SETOEQ: return SPCC::FCC_E;
|
|
|
|
case ISD::SETNE:
|
|
|
|
case ISD::SETUNE: return SPCC::FCC_NE;
|
|
|
|
case ISD::SETLT:
|
|
|
|
case ISD::SETOLT: return SPCC::FCC_L;
|
|
|
|
case ISD::SETGT:
|
|
|
|
case ISD::SETOGT: return SPCC::FCC_G;
|
|
|
|
case ISD::SETLE:
|
|
|
|
case ISD::SETOLE: return SPCC::FCC_LE;
|
|
|
|
case ISD::SETGE:
|
|
|
|
case ISD::SETOGE: return SPCC::FCC_GE;
|
|
|
|
case ISD::SETULT: return SPCC::FCC_UL;
|
|
|
|
case ISD::SETULE: return SPCC::FCC_ULE;
|
|
|
|
case ISD::SETUGT: return SPCC::FCC_UG;
|
|
|
|
case ISD::SETUGE: return SPCC::FCC_UGE;
|
|
|
|
case ISD::SETUO: return SPCC::FCC_U;
|
|
|
|
case ISD::SETO: return SPCC::FCC_O;
|
|
|
|
case ISD::SETONE: return SPCC::FCC_LG;
|
|
|
|
case ISD::SETUEQ: return SPCC::FCC_UE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SparcTargetLowering::SparcTargetLowering(TargetMachine &TM)
|
2009-08-09 04:43:12 +08:00
|
|
|
: TargetLowering(TM, new TargetLoweringObjectFileELF()) {
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 13:41:48 +08:00
|
|
|
// Set up the register classes.
|
2009-08-12 04:47:22 +08:00
|
|
|
addRegisterClass(MVT::i32, SP::IntRegsRegisterClass);
|
|
|
|
addRegisterClass(MVT::f32, SP::FPRegsRegisterClass);
|
|
|
|
addRegisterClass(MVT::f64, SP::DFPRegsRegisterClass);
|
2008-03-17 13:41:48 +08:00
|
|
|
|
|
|
|
// Turn FP extload into load/fextend
|
2009-08-12 04:47:22 +08:00
|
|
|
setLoadExtAction(ISD::EXTLOAD, MVT::f32, Expand);
|
2008-03-17 13:41:48 +08:00
|
|
|
// Sparc doesn't have i1 sign extending load
|
2009-08-12 04:47:22 +08:00
|
|
|
setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote);
|
2008-03-17 13:41:48 +08:00
|
|
|
// Turn FP truncstore into trunc + store.
|
2009-08-12 04:47:22 +08:00
|
|
|
setTruncStoreAction(MVT::f64, MVT::f32, Expand);
|
2008-03-17 13:41:48 +08:00
|
|
|
|
|
|
|
// Custom legalize GlobalAddress nodes into LO/HI parts.
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);
|
|
|
|
setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom);
|
|
|
|
setOperationAction(ISD::ConstantPool , MVT::i32, Custom);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 13:41:48 +08:00
|
|
|
// Sparc doesn't have sext_inreg, replace them with shl/sra
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand);
|
|
|
|
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8 , Expand);
|
|
|
|
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1 , Expand);
|
2008-03-17 13:41:48 +08:00
|
|
|
|
|
|
|
// Sparc has no REM or DIVREM operations.
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::UREM, MVT::i32, Expand);
|
|
|
|
setOperationAction(ISD::SREM, MVT::i32, Expand);
|
|
|
|
setOperationAction(ISD::SDIVREM, MVT::i32, Expand);
|
|
|
|
setOperationAction(ISD::UDIVREM, MVT::i32, Expand);
|
2008-03-17 13:41:48 +08:00
|
|
|
|
|
|
|
// Custom expand fp<->sint
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom);
|
|
|
|
setOperationAction(ISD::SINT_TO_FP, MVT::i32, Custom);
|
2008-03-17 13:41:48 +08:00
|
|
|
|
|
|
|
// Expand fp<->uint
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::FP_TO_UINT, MVT::i32, Expand);
|
|
|
|
setOperationAction(ISD::UINT_TO_FP, MVT::i32, Expand);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2010-11-23 11:31:01 +08:00
|
|
|
setOperationAction(ISD::BITCAST, MVT::f32, Expand);
|
|
|
|
setOperationAction(ISD::BITCAST, MVT::i32, Expand);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 13:41:48 +08:00
|
|
|
// Sparc has no select or setcc: expand to SELECT_CC.
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::SELECT, MVT::i32, Expand);
|
|
|
|
setOperationAction(ISD::SELECT, MVT::f32, Expand);
|
|
|
|
setOperationAction(ISD::SELECT, MVT::f64, Expand);
|
|
|
|
setOperationAction(ISD::SETCC, MVT::i32, Expand);
|
|
|
|
setOperationAction(ISD::SETCC, MVT::f32, Expand);
|
|
|
|
setOperationAction(ISD::SETCC, MVT::f64, Expand);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 13:41:48 +08:00
|
|
|
// Sparc doesn't have BRCOND either, it has BR_CC.
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::BRCOND, MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::BRIND, MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::BR_JT, MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::BR_CC, MVT::i32, Custom);
|
|
|
|
setOperationAction(ISD::BR_CC, MVT::f32, Custom);
|
|
|
|
setOperationAction(ISD::BR_CC, MVT::f64, Custom);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
|
|
|
|
setOperationAction(ISD::SELECT_CC, MVT::f32, Custom);
|
|
|
|
setOperationAction(ISD::SELECT_CC, MVT::f64, Custom);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 13:41:48 +08:00
|
|
|
// SPARC has no intrinsics for these particular operations.
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::MEMBARRIER, MVT::Other, Expand);
|
|
|
|
|
|
|
|
setOperationAction(ISD::FSIN , MVT::f64, Expand);
|
|
|
|
setOperationAction(ISD::FCOS , MVT::f64, Expand);
|
|
|
|
setOperationAction(ISD::FREM , MVT::f64, Expand);
|
|
|
|
setOperationAction(ISD::FSIN , MVT::f32, Expand);
|
|
|
|
setOperationAction(ISD::FCOS , MVT::f32, Expand);
|
|
|
|
setOperationAction(ISD::FREM , MVT::f32, Expand);
|
|
|
|
setOperationAction(ISD::CTPOP, MVT::i32, Expand);
|
|
|
|
setOperationAction(ISD::CTTZ , MVT::i32, Expand);
|
|
|
|
setOperationAction(ISD::CTLZ , MVT::i32, Expand);
|
|
|
|
setOperationAction(ISD::ROTL , MVT::i32, Expand);
|
|
|
|
setOperationAction(ISD::ROTR , MVT::i32, Expand);
|
|
|
|
setOperationAction(ISD::BSWAP, MVT::i32, Expand);
|
|
|
|
setOperationAction(ISD::FCOPYSIGN, MVT::f64, Expand);
|
|
|
|
setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand);
|
|
|
|
setOperationAction(ISD::FPOW , MVT::f64, Expand);
|
|
|
|
setOperationAction(ISD::FPOW , MVT::f32, Expand);
|
|
|
|
|
|
|
|
setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand);
|
|
|
|
setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand);
|
|
|
|
setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand);
|
2008-03-17 13:41:48 +08:00
|
|
|
|
|
|
|
// FIXME: Sparc provides these multiplies, but we don't have them yet.
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand);
|
|
|
|
setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::EH_LABEL, MVT::Other, Expand);
|
2008-03-17 13:41:48 +08:00
|
|
|
|
|
|
|
// VASTART needs to be custom lowered to use the VarArgsFrameIndex.
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::VASTART , MVT::Other, Custom);
|
2008-03-17 13:41:48 +08:00
|
|
|
// VAARG needs to be lowered to not do unaligned accesses for doubles.
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::VAARG , MVT::Other, Custom);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 13:41:48 +08:00
|
|
|
// Use the default implementation.
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::VACOPY , MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::VAEND , MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::STACKSAVE , MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::STACKRESTORE , MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32 , Custom);
|
2008-03-17 13:41:48 +08:00
|
|
|
|
|
|
|
// No debug info support yet.
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::EH_LABEL, MVT::Other, Expand);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 13:41:48 +08:00
|
|
|
setStackPointerRegisterToSaveRestore(SP::O6);
|
|
|
|
|
|
|
|
if (TM.getSubtarget<SparcSubtarget>().isV9())
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::CTPOP, MVT::i32, Legal);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2011-05-07 04:34:06 +08:00
|
|
|
setMinFunctionAlignment(2);
|
|
|
|
|
2008-03-17 13:41:48 +08:00
|
|
|
computeRegisterProperties();
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *SparcTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
|
|
|
switch (Opcode) {
|
|
|
|
default: return 0;
|
|
|
|
case SPISD::CMPICC: return "SPISD::CMPICC";
|
|
|
|
case SPISD::CMPFCC: return "SPISD::CMPFCC";
|
|
|
|
case SPISD::BRICC: return "SPISD::BRICC";
|
|
|
|
case SPISD::BRFCC: return "SPISD::BRFCC";
|
|
|
|
case SPISD::SELECT_ICC: return "SPISD::SELECT_ICC";
|
|
|
|
case SPISD::SELECT_FCC: return "SPISD::SELECT_FCC";
|
|
|
|
case SPISD::Hi: return "SPISD::Hi";
|
|
|
|
case SPISD::Lo: return "SPISD::Lo";
|
|
|
|
case SPISD::FTOI: return "SPISD::FTOI";
|
|
|
|
case SPISD::ITOF: return "SPISD::ITOF";
|
|
|
|
case SPISD::CALL: return "SPISD::CALL";
|
|
|
|
case SPISD::RET_FLAG: return "SPISD::RET_FLAG";
|
2011-01-12 13:08:36 +08:00
|
|
|
case SPISD::GLOBAL_BASE_REG: return "SPISD::GLOBAL_BASE_REG";
|
2011-01-22 06:00:00 +08:00
|
|
|
case SPISD::FLUSHW: return "SPISD::FLUSHW";
|
2008-03-17 13:41:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// isMaskedValueZeroForTargetNode - Return true if 'Op & Mask' is known to
|
|
|
|
/// be zero. Op is expected to be a target specific node. Used by DAG
|
|
|
|
/// combiner.
|
2008-07-28 05:46:04 +08:00
|
|
|
void SparcTargetLowering::computeMaskedBitsForTargetNode(const SDValue Op,
|
2008-03-17 13:41:48 +08:00
|
|
|
const APInt &Mask,
|
2008-10-11 04:27:31 +08:00
|
|
|
APInt &KnownZero,
|
2008-03-17 13:41:48 +08:00
|
|
|
APInt &KnownOne,
|
|
|
|
const SelectionDAG &DAG,
|
|
|
|
unsigned Depth) const {
|
|
|
|
APInt KnownZero2, KnownOne2;
|
|
|
|
KnownZero = KnownOne = APInt(Mask.getBitWidth(), 0); // Don't know anything.
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 13:41:48 +08:00
|
|
|
switch (Op.getOpcode()) {
|
|
|
|
default: break;
|
|
|
|
case SPISD::SELECT_ICC:
|
|
|
|
case SPISD::SELECT_FCC:
|
|
|
|
DAG.ComputeMaskedBits(Op.getOperand(1), Mask, KnownZero, KnownOne,
|
|
|
|
Depth+1);
|
|
|
|
DAG.ComputeMaskedBits(Op.getOperand(0), Mask, KnownZero2, KnownOne2,
|
|
|
|
Depth+1);
|
2008-10-11 04:27:31 +08:00
|
|
|
assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?");
|
|
|
|
assert((KnownZero2 & KnownOne2) == 0 && "Bits known to be one AND zero?");
|
|
|
|
|
2008-03-17 13:41:48 +08:00
|
|
|
// Only known if known in both the LHS and RHS.
|
|
|
|
KnownOne &= KnownOne2;
|
|
|
|
KnownZero &= KnownZero2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
// Look at LHS/RHS/CC and see if they are a lowered setcc instruction. If so
|
|
|
|
// set LHS/RHS and SPCC to the LHS/RHS of the setcc and SPCC to the condition.
|
2008-07-28 05:46:04 +08:00
|
|
|
static void LookThroughSetCC(SDValue &LHS, SDValue &RHS,
|
2008-03-17 11:21:36 +08:00
|
|
|
ISD::CondCode CC, unsigned &SPCC) {
|
2008-09-13 00:56:44 +08:00
|
|
|
if (isa<ConstantSDNode>(RHS) &&
|
2010-06-18 22:22:04 +08:00
|
|
|
cast<ConstantSDNode>(RHS)->isNullValue() &&
|
2008-10-11 04:27:31 +08:00
|
|
|
CC == ISD::SETNE &&
|
2008-03-17 11:21:36 +08:00
|
|
|
((LHS.getOpcode() == SPISD::SELECT_ICC &&
|
|
|
|
LHS.getOperand(3).getOpcode() == SPISD::CMPICC) ||
|
|
|
|
(LHS.getOpcode() == SPISD::SELECT_FCC &&
|
|
|
|
LHS.getOperand(3).getOpcode() == SPISD::CMPFCC)) &&
|
|
|
|
isa<ConstantSDNode>(LHS.getOperand(0)) &&
|
|
|
|
isa<ConstantSDNode>(LHS.getOperand(1)) &&
|
2010-06-18 22:22:04 +08:00
|
|
|
cast<ConstantSDNode>(LHS.getOperand(0))->isOne() &&
|
|
|
|
cast<ConstantSDNode>(LHS.getOperand(1))->isNullValue()) {
|
2008-07-28 05:46:04 +08:00
|
|
|
SDValue CMPCC = LHS.getOperand(3);
|
2008-09-13 00:56:44 +08:00
|
|
|
SPCC = cast<ConstantSDNode>(LHS.getOperand(2))->getZExtValue();
|
2008-03-17 11:21:36 +08:00
|
|
|
LHS = CMPCC.getOperand(0);
|
|
|
|
RHS = CMPCC.getOperand(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-23 11:31:01 +08:00
|
|
|
SDValue SparcTargetLowering::LowerGlobalAddress(SDValue Op,
|
2010-04-17 23:26:15 +08:00
|
|
|
SelectionDAG &DAG) const {
|
2010-04-15 09:51:59 +08:00
|
|
|
const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
|
2009-02-07 05:50:26 +08:00
|
|
|
// FIXME there isn't really any debug info here
|
|
|
|
DebugLoc dl = Op.getDebugLoc();
|
2010-07-07 06:08:15 +08:00
|
|
|
SDValue GA = DAG.getTargetGlobalAddress(GV, dl, MVT::i32);
|
2009-08-12 04:47:22 +08:00
|
|
|
SDValue Hi = DAG.getNode(SPISD::Hi, dl, MVT::i32, GA);
|
|
|
|
SDValue Lo = DAG.getNode(SPISD::Lo, dl, MVT::i32, GA);
|
2009-09-16 01:46:24 +08:00
|
|
|
|
2010-11-23 11:31:01 +08:00
|
|
|
if (getTargetMachine().getRelocationModel() != Reloc::PIC_)
|
2009-09-16 01:46:24 +08:00
|
|
|
return DAG.getNode(ISD::ADD, dl, MVT::i32, Lo, Hi);
|
2010-11-23 11:31:01 +08:00
|
|
|
|
2009-09-16 01:46:24 +08:00
|
|
|
SDValue GlobalBase = DAG.getNode(SPISD::GLOBAL_BASE_REG, dl,
|
|
|
|
getPointerTy());
|
|
|
|
SDValue RelAddr = DAG.getNode(ISD::ADD, dl, MVT::i32, Lo, Hi);
|
2010-11-23 11:31:01 +08:00
|
|
|
SDValue AbsAddr = DAG.getNode(ISD::ADD, dl, MVT::i32,
|
2009-09-16 01:46:24 +08:00
|
|
|
GlobalBase, RelAddr);
|
2010-11-23 11:31:01 +08:00
|
|
|
return DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(),
|
2010-09-21 14:44:06 +08:00
|
|
|
AbsAddr, MachinePointerInfo(), false, false, 0);
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
|
|
|
|
2009-09-16 01:46:24 +08:00
|
|
|
SDValue SparcTargetLowering::LowerConstantPool(SDValue Op,
|
2010-04-17 23:26:15 +08:00
|
|
|
SelectionDAG &DAG) const {
|
2008-03-17 11:21:36 +08:00
|
|
|
ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op);
|
2009-02-07 05:50:26 +08:00
|
|
|
// FIXME there isn't really any debug info here
|
|
|
|
DebugLoc dl = Op.getDebugLoc();
|
2010-04-15 09:51:59 +08:00
|
|
|
const Constant *C = N->getConstVal();
|
2009-08-12 04:47:22 +08:00
|
|
|
SDValue CP = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment());
|
|
|
|
SDValue Hi = DAG.getNode(SPISD::Hi, dl, MVT::i32, CP);
|
|
|
|
SDValue Lo = DAG.getNode(SPISD::Lo, dl, MVT::i32, CP);
|
2010-11-23 11:31:01 +08:00
|
|
|
if (getTargetMachine().getRelocationModel() != Reloc::PIC_)
|
2009-09-16 01:46:24 +08:00
|
|
|
return DAG.getNode(ISD::ADD, dl, MVT::i32, Lo, Hi);
|
|
|
|
|
2010-11-23 11:31:01 +08:00
|
|
|
SDValue GlobalBase = DAG.getNode(SPISD::GLOBAL_BASE_REG, dl,
|
2009-09-16 01:46:24 +08:00
|
|
|
getPointerTy());
|
|
|
|
SDValue RelAddr = DAG.getNode(ISD::ADD, dl, MVT::i32, Lo, Hi);
|
|
|
|
SDValue AbsAddr = DAG.getNode(ISD::ADD, dl, MVT::i32,
|
|
|
|
GlobalBase, RelAddr);
|
2010-11-23 11:31:01 +08:00
|
|
|
return DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(),
|
2010-09-21 14:44:06 +08:00
|
|
|
AbsAddr, MachinePointerInfo(), false, false, 0);
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
|
|
|
|
2008-07-28 05:46:04 +08:00
|
|
|
static SDValue LowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG) {
|
2009-02-07 08:55:49 +08:00
|
|
|
DebugLoc dl = Op.getDebugLoc();
|
2008-03-17 11:21:36 +08:00
|
|
|
// Convert the fp value to integer in an FP register.
|
2009-08-12 04:47:22 +08:00
|
|
|
assert(Op.getValueType() == MVT::i32);
|
|
|
|
Op = DAG.getNode(SPISD::FTOI, dl, MVT::f32, Op.getOperand(0));
|
2010-11-23 11:31:01 +08:00
|
|
|
return DAG.getNode(ISD::BITCAST, dl, MVT::i32, Op);
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
|
|
|
|
2008-07-28 05:46:04 +08:00
|
|
|
static SDValue LowerSINT_TO_FP(SDValue Op, SelectionDAG &DAG) {
|
2009-02-07 08:55:49 +08:00
|
|
|
DebugLoc dl = Op.getDebugLoc();
|
2009-08-12 04:47:22 +08:00
|
|
|
assert(Op.getOperand(0).getValueType() == MVT::i32);
|
2010-11-23 11:31:01 +08:00
|
|
|
SDValue Tmp = DAG.getNode(ISD::BITCAST, dl, MVT::f32, Op.getOperand(0));
|
2008-03-17 11:21:36 +08:00
|
|
|
// Convert the int value to FP in an FP register.
|
2009-02-07 08:55:49 +08:00
|
|
|
return DAG.getNode(SPISD::ITOF, dl, Op.getValueType(), Tmp);
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
|
|
|
|
2008-07-28 05:46:04 +08:00
|
|
|
static SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) {
|
|
|
|
SDValue Chain = Op.getOperand(0);
|
2008-03-17 11:21:36 +08:00
|
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get();
|
2008-07-28 05:46:04 +08:00
|
|
|
SDValue LHS = Op.getOperand(2);
|
|
|
|
SDValue RHS = Op.getOperand(3);
|
|
|
|
SDValue Dest = Op.getOperand(4);
|
2009-02-06 06:07:54 +08:00
|
|
|
DebugLoc dl = Op.getDebugLoc();
|
2008-03-17 11:21:36 +08:00
|
|
|
unsigned Opc, SPCC = ~0U;
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
// If this is a br_cc of a "setcc", and if the setcc got lowered into
|
|
|
|
// an CMP[IF]CC/SELECT_[IF]CC pair, find the original compared values.
|
|
|
|
LookThroughSetCC(LHS, RHS, CC, SPCC);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
// Get the condition flag.
|
2008-07-28 05:46:04 +08:00
|
|
|
SDValue CompareFlag;
|
2009-08-12 04:47:22 +08:00
|
|
|
if (LHS.getValueType() == MVT::i32) {
|
2009-08-11 06:56:29 +08:00
|
|
|
std::vector<EVT> VTs;
|
2009-08-12 04:47:22 +08:00
|
|
|
VTs.push_back(MVT::i32);
|
2010-12-21 10:38:05 +08:00
|
|
|
VTs.push_back(MVT::Glue);
|
2008-07-28 05:46:04 +08:00
|
|
|
SDValue Ops[2] = { LHS, RHS };
|
2009-02-06 06:07:54 +08:00
|
|
|
CompareFlag = DAG.getNode(SPISD::CMPICC, dl, VTs, Ops, 2).getValue(1);
|
2008-03-17 11:21:36 +08:00
|
|
|
if (SPCC == ~0U) SPCC = IntCondCCodeToICC(CC);
|
|
|
|
Opc = SPISD::BRICC;
|
|
|
|
} else {
|
2010-12-21 10:38:05 +08:00
|
|
|
CompareFlag = DAG.getNode(SPISD::CMPFCC, dl, MVT::Glue, LHS, RHS);
|
2008-03-17 11:21:36 +08:00
|
|
|
if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC);
|
|
|
|
Opc = SPISD::BRFCC;
|
|
|
|
}
|
2009-08-12 04:47:22 +08:00
|
|
|
return DAG.getNode(Opc, dl, MVT::Other, Chain, Dest,
|
|
|
|
DAG.getConstant(SPCC, MVT::i32), CompareFlag);
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
|
|
|
|
2008-07-28 05:46:04 +08:00
|
|
|
static SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) {
|
|
|
|
SDValue LHS = Op.getOperand(0);
|
|
|
|
SDValue RHS = Op.getOperand(1);
|
2008-03-17 11:21:36 +08:00
|
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
|
2008-07-28 05:46:04 +08:00
|
|
|
SDValue TrueVal = Op.getOperand(2);
|
|
|
|
SDValue FalseVal = Op.getOperand(3);
|
2009-02-06 06:07:54 +08:00
|
|
|
DebugLoc dl = Op.getDebugLoc();
|
2008-03-17 11:21:36 +08:00
|
|
|
unsigned Opc, SPCC = ~0U;
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
// If this is a select_cc of a "setcc", and if the setcc got lowered into
|
|
|
|
// an CMP[IF]CC/SELECT_[IF]CC pair, find the original compared values.
|
|
|
|
LookThroughSetCC(LHS, RHS, CC, SPCC);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-07-28 05:46:04 +08:00
|
|
|
SDValue CompareFlag;
|
2009-08-12 04:47:22 +08:00
|
|
|
if (LHS.getValueType() == MVT::i32) {
|
2009-08-11 06:56:29 +08:00
|
|
|
std::vector<EVT> VTs;
|
2008-03-17 11:21:36 +08:00
|
|
|
VTs.push_back(LHS.getValueType()); // subcc returns a value
|
2010-12-21 10:38:05 +08:00
|
|
|
VTs.push_back(MVT::Glue);
|
2008-07-28 05:46:04 +08:00
|
|
|
SDValue Ops[2] = { LHS, RHS };
|
2009-02-06 06:07:54 +08:00
|
|
|
CompareFlag = DAG.getNode(SPISD::CMPICC, dl, VTs, Ops, 2).getValue(1);
|
2008-03-17 11:21:36 +08:00
|
|
|
Opc = SPISD::SELECT_ICC;
|
|
|
|
if (SPCC == ~0U) SPCC = IntCondCCodeToICC(CC);
|
|
|
|
} else {
|
2010-12-21 10:38:05 +08:00
|
|
|
CompareFlag = DAG.getNode(SPISD::CMPFCC, dl, MVT::Glue, LHS, RHS);
|
2008-03-17 11:21:36 +08:00
|
|
|
Opc = SPISD::SELECT_FCC;
|
|
|
|
if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC);
|
|
|
|
}
|
2009-02-06 06:07:54 +08:00
|
|
|
return DAG.getNode(Opc, dl, TrueVal.getValueType(), TrueVal, FalseVal,
|
2009-08-12 04:47:22 +08:00
|
|
|
DAG.getConstant(SPCC, MVT::i32), CompareFlag);
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
|
|
|
|
2008-07-28 05:46:04 +08:00
|
|
|
static SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG,
|
2010-04-17 23:26:15 +08:00
|
|
|
const SparcTargetLowering &TLI) {
|
2010-04-17 22:41:14 +08:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
|
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
// vastart just stores the address of the VarArgsFrameIndex slot into the
|
|
|
|
// memory location argument.
|
2009-02-08 03:59:05 +08:00
|
|
|
DebugLoc dl = Op.getDebugLoc();
|
2010-04-17 22:41:14 +08:00
|
|
|
SDValue Offset =
|
|
|
|
DAG.getNode(ISD::ADD, dl, MVT::i32,
|
|
|
|
DAG.getRegister(SP::I6, MVT::i32),
|
|
|
|
DAG.getConstant(FuncInfo->getVarArgsFrameOffset(),
|
|
|
|
MVT::i32));
|
2008-03-17 11:21:36 +08:00
|
|
|
const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
|
2010-09-22 02:41:36 +08:00
|
|
|
return DAG.getStore(Op.getOperand(0), dl, Offset, Op.getOperand(1),
|
|
|
|
MachinePointerInfo(SV), false, false, 0);
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
|
|
|
|
2008-07-28 05:46:04 +08:00
|
|
|
static SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) {
|
2008-08-29 05:40:38 +08:00
|
|
|
SDNode *Node = Op.getNode();
|
2009-08-11 06:56:29 +08:00
|
|
|
EVT VT = Node->getValueType(0);
|
2008-07-28 05:46:04 +08:00
|
|
|
SDValue InChain = Node->getOperand(0);
|
|
|
|
SDValue VAListPtr = Node->getOperand(1);
|
2008-03-17 11:21:36 +08:00
|
|
|
const Value *SV = cast<SrcValueSDNode>(Node->getOperand(2))->getValue();
|
2009-02-05 04:06:27 +08:00
|
|
|
DebugLoc dl = Node->getDebugLoc();
|
2010-09-21 14:44:06 +08:00
|
|
|
SDValue VAList = DAG.getLoad(MVT::i32, dl, InChain, VAListPtr,
|
|
|
|
MachinePointerInfo(SV), false, false, 0);
|
2008-03-17 11:21:36 +08:00
|
|
|
// Increment the pointer, VAList, to the next vaarg
|
2009-08-12 04:47:22 +08:00
|
|
|
SDValue NextPtr = DAG.getNode(ISD::ADD, dl, MVT::i32, VAList,
|
2008-06-06 20:08:01 +08:00
|
|
|
DAG.getConstant(VT.getSizeInBits()/8,
|
2009-08-12 04:47:22 +08:00
|
|
|
MVT::i32));
|
2008-03-17 11:21:36 +08:00
|
|
|
// Store the incremented VAList to the legalized pointer
|
2009-02-05 04:06:27 +08:00
|
|
|
InChain = DAG.getStore(VAList.getValue(1), dl, NextPtr,
|
2010-09-22 02:41:36 +08:00
|
|
|
VAListPtr, MachinePointerInfo(SV), false, false, 0);
|
2008-03-17 11:21:36 +08:00
|
|
|
// Load the actual argument out of the pointer VAList, unless this is an
|
|
|
|
// f64 load.
|
2009-08-12 04:47:22 +08:00
|
|
|
if (VT != MVT::f64)
|
2010-09-21 14:44:06 +08:00
|
|
|
return DAG.getLoad(VT, dl, InChain, VAList, MachinePointerInfo(),
|
|
|
|
false, false, 0);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
// Otherwise, load it as i64, then do a bitconvert.
|
2010-09-21 14:44:06 +08:00
|
|
|
SDValue V = DAG.getLoad(MVT::i64, dl, InChain, VAList, MachinePointerInfo(),
|
2010-02-16 00:57:02 +08:00
|
|
|
false, false, 0);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
// Bit-Convert the value to f64.
|
2008-07-28 05:46:04 +08:00
|
|
|
SDValue Ops[2] = {
|
2010-11-23 11:31:01 +08:00
|
|
|
DAG.getNode(ISD::BITCAST, dl, MVT::f64, V),
|
2008-03-17 11:21:36 +08:00
|
|
|
V.getValue(1)
|
|
|
|
};
|
2009-02-05 04:06:27 +08:00
|
|
|
return DAG.getMergeValues(Ops, 2, dl);
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
|
|
|
|
2008-07-28 05:46:04 +08:00
|
|
|
static SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) {
|
|
|
|
SDValue Chain = Op.getOperand(0); // Legalize the chain.
|
|
|
|
SDValue Size = Op.getOperand(1); // Legalize the size.
|
2009-02-05 07:02:30 +08:00
|
|
|
DebugLoc dl = Op.getDebugLoc();
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
unsigned SPReg = SP::O6;
|
2009-08-12 04:47:22 +08:00
|
|
|
SDValue SP = DAG.getCopyFromReg(Chain, dl, SPReg, MVT::i32);
|
|
|
|
SDValue NewSP = DAG.getNode(ISD::SUB, dl, MVT::i32, SP, Size); // Value
|
2009-02-05 07:02:30 +08:00
|
|
|
Chain = DAG.getCopyToReg(SP.getValue(1), dl, SPReg, NewSP); // Output chain
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
// The resultant pointer is actually 16 words from the bottom of the stack,
|
|
|
|
// to provide a register spill area.
|
2009-08-12 04:47:22 +08:00
|
|
|
SDValue NewVal = DAG.getNode(ISD::ADD, dl, MVT::i32, NewSP,
|
|
|
|
DAG.getConstant(96, MVT::i32));
|
2008-07-28 05:46:04 +08:00
|
|
|
SDValue Ops[2] = { NewVal, Chain };
|
2009-02-05 07:02:30 +08:00
|
|
|
return DAG.getMergeValues(Ops, 2, dl);
|
2008-03-17 11:21:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-22 06:00:00 +08:00
|
|
|
static SDValue getFLUSHW(SDValue Op, SelectionDAG &DAG) {
|
2011-01-12 13:08:36 +08:00
|
|
|
DebugLoc dl = Op.getDebugLoc();
|
2011-01-22 06:00:00 +08:00
|
|
|
SDValue Chain = DAG.getNode(SPISD::FLUSHW,
|
2011-01-12 13:08:36 +08:00
|
|
|
dl, MVT::Other, DAG.getEntryNode());
|
|
|
|
return Chain;
|
|
|
|
}
|
|
|
|
|
|
|
|
static SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) {
|
|
|
|
MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
|
|
|
|
MFI->setFrameAddressIsTaken(true);
|
|
|
|
|
|
|
|
EVT VT = Op.getValueType();
|
|
|
|
DebugLoc dl = Op.getDebugLoc();
|
|
|
|
unsigned FrameReg = SP::I6;
|
|
|
|
|
|
|
|
uint64_t depth = Op.getConstantOperandVal(0);
|
|
|
|
|
|
|
|
SDValue FrameAddr;
|
2011-01-22 06:00:00 +08:00
|
|
|
if (depth == 0)
|
2011-01-12 13:08:36 +08:00
|
|
|
FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, FrameReg, VT);
|
|
|
|
else {
|
|
|
|
// flush first to make sure the windowed registers' values are in stack
|
2011-01-22 06:00:00 +08:00
|
|
|
SDValue Chain = getFLUSHW(Op, DAG);
|
2011-01-12 13:08:36 +08:00
|
|
|
FrameAddr = DAG.getCopyFromReg(Chain, dl, FrameReg, VT);
|
2011-01-22 06:00:00 +08:00
|
|
|
|
2011-01-12 13:08:36 +08:00
|
|
|
for (uint64_t i = 0; i != depth; ++i) {
|
2011-01-22 06:00:00 +08:00
|
|
|
SDValue Ptr = DAG.getNode(ISD::ADD,
|
2011-01-12 13:08:36 +08:00
|
|
|
dl, MVT::i32,
|
|
|
|
FrameAddr, DAG.getIntPtrConstant(56));
|
2011-01-22 06:00:00 +08:00
|
|
|
FrameAddr = DAG.getLoad(MVT::i32, dl,
|
|
|
|
Chain,
|
2011-01-12 13:08:36 +08:00
|
|
|
Ptr,
|
|
|
|
MachinePointerInfo(), false, false, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FrameAddr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) {
|
|
|
|
MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
|
|
|
|
MFI->setReturnAddressIsTaken(true);
|
|
|
|
|
|
|
|
EVT VT = Op.getValueType();
|
|
|
|
DebugLoc dl = Op.getDebugLoc();
|
|
|
|
unsigned RetReg = SP::I7;
|
|
|
|
|
|
|
|
uint64_t depth = Op.getConstantOperandVal(0);
|
|
|
|
|
|
|
|
SDValue RetAddr;
|
2011-01-22 06:00:00 +08:00
|
|
|
if (depth == 0)
|
2011-01-12 13:08:36 +08:00
|
|
|
RetAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, RetReg, VT);
|
|
|
|
else {
|
|
|
|
// flush first to make sure the windowed registers' values are in stack
|
2011-01-22 06:00:00 +08:00
|
|
|
SDValue Chain = getFLUSHW(Op, DAG);
|
2011-01-12 13:08:36 +08:00
|
|
|
RetAddr = DAG.getCopyFromReg(Chain, dl, SP::I6, VT);
|
2011-01-22 06:00:00 +08:00
|
|
|
|
2011-01-12 13:08:36 +08:00
|
|
|
for (uint64_t i = 0; i != depth; ++i) {
|
2011-01-22 06:00:00 +08:00
|
|
|
SDValue Ptr = DAG.getNode(ISD::ADD,
|
2011-01-12 13:08:36 +08:00
|
|
|
dl, MVT::i32,
|
2011-01-22 06:00:00 +08:00
|
|
|
RetAddr,
|
2011-01-12 13:08:36 +08:00
|
|
|
DAG.getIntPtrConstant((i == depth-1)?60:56));
|
2011-01-22 06:00:00 +08:00
|
|
|
RetAddr = DAG.getLoad(MVT::i32, dl,
|
|
|
|
Chain,
|
2011-01-12 13:08:36 +08:00
|
|
|
Ptr,
|
|
|
|
MachinePointerInfo(), false, false, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return RetAddr;
|
|
|
|
}
|
|
|
|
|
2008-07-28 05:46:04 +08:00
|
|
|
SDValue SparcTargetLowering::
|
2010-04-17 23:26:15 +08:00
|
|
|
LowerOperation(SDValue Op, SelectionDAG &DAG) const {
|
2008-03-17 11:21:36 +08:00
|
|
|
switch (Op.getOpcode()) {
|
2009-07-15 00:55:14 +08:00
|
|
|
default: llvm_unreachable("Should not custom lower this!");
|
2011-01-12 13:08:36 +08:00
|
|
|
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);
|
|
|
|
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
|
2008-03-17 11:21:36 +08:00
|
|
|
case ISD::GlobalTLSAddress:
|
2009-07-15 00:55:14 +08:00
|
|
|
llvm_unreachable("TLS not implemented for Sparc.");
|
2009-09-16 01:46:24 +08:00
|
|
|
case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG);
|
|
|
|
case ISD::ConstantPool: return LowerConstantPool(Op, DAG);
|
2008-03-17 11:21:36 +08:00
|
|
|
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::VASTART: return LowerVASTART(Op, DAG, *this);
|
|
|
|
case ISD::VAARG: return LowerVAARG(Op, DAG);
|
|
|
|
case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MachineBasicBlock *
|
|
|
|
SparcTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
|
2010-05-01 08:01:06 +08:00
|
|
|
MachineBasicBlock *BB) const {
|
2008-03-17 11:21:36 +08:00
|
|
|
const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo();
|
|
|
|
unsigned BROpcode;
|
|
|
|
unsigned CC;
|
2009-02-13 10:31:35 +08:00
|
|
|
DebugLoc dl = MI->getDebugLoc();
|
2008-03-17 11:21:36 +08:00
|
|
|
// Figure out the conditional branch opcode to use for this select_cc.
|
|
|
|
switch (MI->getOpcode()) {
|
2009-07-15 00:55:14 +08:00
|
|
|
default: llvm_unreachable("Unknown SELECT_CC!");
|
2008-03-17 11:21:36 +08:00
|
|
|
case SP::SELECT_CC_Int_ICC:
|
|
|
|
case SP::SELECT_CC_FP_ICC:
|
|
|
|
case SP::SELECT_CC_DFP_ICC:
|
|
|
|
BROpcode = SP::BCOND;
|
|
|
|
break;
|
|
|
|
case SP::SELECT_CC_Int_FCC:
|
|
|
|
case SP::SELECT_CC_FP_FCC:
|
|
|
|
case SP::SELECT_CC_DFP_FCC:
|
|
|
|
BROpcode = SP::FBCOND;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
CC = (SPCC::CondCodes)MI->getOperand(3).getImm();
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
// To "insert" a SELECT_CC instruction, we actually have to insert the diamond
|
|
|
|
// control-flow pattern. The incoming instruction knows the destination vreg
|
|
|
|
// to set, the condition code register to branch on, the true/false values to
|
|
|
|
// select between, and a branch opcode to use.
|
|
|
|
const BasicBlock *LLVM_BB = BB->getBasicBlock();
|
2008-07-08 07:14:23 +08:00
|
|
|
MachineFunction::iterator It = BB;
|
2008-03-17 11:21:36 +08:00
|
|
|
++It;
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
// thisMBB:
|
|
|
|
// ...
|
|
|
|
// TrueVal = ...
|
|
|
|
// [f]bCC copy1MBB
|
|
|
|
// fallthrough --> copy0MBB
|
|
|
|
MachineBasicBlock *thisMBB = BB;
|
|
|
|
MachineFunction *F = BB->getParent();
|
2008-07-08 07:14:23 +08:00
|
|
|
MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB);
|
|
|
|
MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB);
|
2010-12-29 04:39:17 +08:00
|
|
|
F->insert(It, copy0MBB);
|
|
|
|
F->insert(It, sinkMBB);
|
2010-07-07 04:24:04 +08:00
|
|
|
|
|
|
|
// Transfer the remainder of BB and its successor edges to sinkMBB.
|
|
|
|
sinkMBB->splice(sinkMBB->begin(), BB,
|
|
|
|
llvm::next(MachineBasicBlock::iterator(MI)),
|
|
|
|
BB->end());
|
|
|
|
sinkMBB->transferSuccessorsAndUpdatePHIs(BB);
|
|
|
|
|
|
|
|
// Add the true and fallthrough blocks as its successors.
|
|
|
|
BB->addSuccessor(copy0MBB);
|
|
|
|
BB->addSuccessor(sinkMBB);
|
|
|
|
|
2009-02-13 10:31:35 +08:00
|
|
|
BuildMI(BB, dl, TII.get(BROpcode)).addMBB(sinkMBB).addImm(CC);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
// copy0MBB:
|
|
|
|
// %FalseValue = ...
|
|
|
|
// # fallthrough to sinkMBB
|
|
|
|
BB = copy0MBB;
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
// Update machine-CFG edges
|
|
|
|
BB->addSuccessor(sinkMBB);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2008-03-17 11:21:36 +08:00
|
|
|
// sinkMBB:
|
|
|
|
// %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ]
|
|
|
|
// ...
|
|
|
|
BB = sinkMBB;
|
2010-07-07 04:24:04 +08:00
|
|
|
BuildMI(*BB, BB->begin(), dl, TII.get(SP::PHI), MI->getOperand(0).getReg())
|
2008-03-17 11:21:36 +08:00
|
|
|
.addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB)
|
|
|
|
.addReg(MI->getOperand(1).getReg()).addMBB(thisMBB);
|
2008-10-11 04:27:31 +08:00
|
|
|
|
2010-07-07 04:24:04 +08:00
|
|
|
MI->eraseFromParent(); // The pseudo instruction is gone now.
|
2008-03-17 11:21:36 +08:00
|
|
|
return BB;
|
|
|
|
}
|
2008-10-11 04:28:10 +08:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Sparc Inline Assembly Support
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
/// getConstraintType - Given a constraint letter, return the type of
|
|
|
|
/// constraint it is for this target.
|
|
|
|
SparcTargetLowering::ConstraintType
|
|
|
|
SparcTargetLowering::getConstraintType(const std::string &Constraint) const {
|
|
|
|
if (Constraint.size() == 1) {
|
|
|
|
switch (Constraint[0]) {
|
|
|
|
default: break;
|
|
|
|
case 'r': return C_RegisterClass;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TargetLowering::getConstraintType(Constraint);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<unsigned, const TargetRegisterClass*>
|
|
|
|
SparcTargetLowering::getRegForInlineAsmConstraint(const std::string &Constraint,
|
2009-08-11 06:56:29 +08:00
|
|
|
EVT VT) const {
|
2008-10-11 04:28:10 +08:00
|
|
|
if (Constraint.size() == 1) {
|
|
|
|
switch (Constraint[0]) {
|
|
|
|
case 'r':
|
|
|
|
return std::make_pair(0U, SP::IntRegsRegisterClass);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<unsigned> SparcTargetLowering::
|
|
|
|
getRegClassForInlineAsmConstraint(const std::string &Constraint,
|
2009-08-11 06:56:29 +08:00
|
|
|
EVT VT) const {
|
2008-10-11 04:28:10 +08:00
|
|
|
if (Constraint.size() != 1)
|
|
|
|
return std::vector<unsigned>();
|
|
|
|
|
|
|
|
switch (Constraint[0]) {
|
|
|
|
default: break;
|
|
|
|
case 'r':
|
|
|
|
return make_vector<unsigned>(SP::L0, SP::L1, SP::L2, SP::L3,
|
|
|
|
SP::L4, SP::L5, SP::L6, SP::L7,
|
|
|
|
SP::I0, SP::I1, SP::I2, SP::I3,
|
|
|
|
SP::I4, SP::I5,
|
|
|
|
SP::O0, SP::O1, SP::O2, SP::O3,
|
|
|
|
SP::O4, SP::O5, SP::O7, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return std::vector<unsigned>();
|
|
|
|
}
|
Teach DAGCombine to fold constant offsets into GlobalAddress nodes,
and add a TargetLowering hook for it to use to determine when this
is legal (i.e. not in PIC mode, etc.)
This allows instruction selection to emit folded constant offsets
in more cases, such as the included testcase, eliminating the need
for explicit arithmetic instructions.
This eliminates the need for the C++ code in X86ISelDAGToDAG.cpp
that attempted to achieve the same effect, but wasn't as effective.
Also, fix handling of offsets in GlobalAddressSDNodes in several
places, including changing GlobalAddressSDNode's offset from
int to int64_t.
The Mips, Alpha, Sparc, and CellSPU targets appear to be
unaware of GlobalAddress offsets currently, so set the hook to
false on those targets.
llvm-svn: 57748
2008-10-18 10:06:02 +08:00
|
|
|
|
|
|
|
bool
|
|
|
|
SparcTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const {
|
|
|
|
// The Sparc target isn't yet aware of offsets.
|
|
|
|
return false;
|
|
|
|
}
|