2008-03-17 03:21:36 +00: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"
|
2010-04-17 14:41:14 +00:00
|
|
|
#include "SparcMachineFunctionInfo.h"
|
2012-12-03 16:50:05 +00:00
|
|
|
#include "SparcTargetMachine.h"
|
2013-04-14 01:33:32 +00:00
|
|
|
#include "MCTargetDesc/SparcBaseInfo.h"
|
2008-03-17 05:41:48 +00:00
|
|
|
#include "llvm/CodeGen/CallingConvLower.h"
|
2008-03-17 03:21:36 +00: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-15 22:37:53 +00:00
|
|
|
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
|
2013-01-02 11:36:10 +00:00
|
|
|
#include "llvm/IR/DerivedTypes.h"
|
|
|
|
#include "llvm/IR/Function.h"
|
|
|
|
#include "llvm/IR/Module.h"
|
2009-07-11 20:10:48 +00:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2008-03-17 03:21:36 +00:00
|
|
|
using namespace llvm;
|
|
|
|
|
2008-03-17 05:41:48 +00:00
|
|
|
|
2008-03-17 03:21:36 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
2008-03-17 05:41:48 +00:00
|
|
|
// Calling Convention Implementation
|
2008-03-17 03:21:36 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2011-01-22 13:05:16 +00: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 06:09:55 +00:00
|
|
|
static bool CC_Sparc_Assign_f64(unsigned &ValNo, MVT &ValVT,
|
|
|
|
MVT &LocVT, CCValAssign::LocInfo &LocInfo,
|
|
|
|
ISD::ArgFlagsTy &ArgFlags, CCState &State)
|
|
|
|
{
|
2012-03-11 07:57:25 +00:00
|
|
|
static const uint16_t RegList[] = {
|
2011-01-18 06:09:55 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-04-06 18:32:12 +00:00
|
|
|
// Allocate a full-sized argument for the 64-bit ABI.
|
|
|
|
static bool CC_Sparc64_Full(unsigned &ValNo, MVT &ValVT,
|
|
|
|
MVT &LocVT, CCValAssign::LocInfo &LocInfo,
|
|
|
|
ISD::ArgFlagsTy &ArgFlags, CCState &State) {
|
|
|
|
assert((LocVT == MVT::f32 || LocVT.getSizeInBits() == 64) &&
|
|
|
|
"Can't handle non-64 bits locations");
|
|
|
|
|
|
|
|
// Stack space is allocated for all arguments starting from [%fp+BIAS+128].
|
|
|
|
unsigned Offset = State.AllocateStack(8, 8);
|
|
|
|
unsigned Reg = 0;
|
|
|
|
|
|
|
|
if (LocVT == MVT::i64 && Offset < 6*8)
|
|
|
|
// Promote integers to %i0-%i5.
|
|
|
|
Reg = SP::I0 + Offset/8;
|
|
|
|
else if (LocVT == MVT::f64 && Offset < 16*8)
|
|
|
|
// Promote doubles to %d0-%d30. (Which LLVM calls D0-D15).
|
|
|
|
Reg = SP::D0 + Offset/8;
|
|
|
|
else if (LocVT == MVT::f32 && Offset < 16*8)
|
|
|
|
// Promote floats to %f1, %f3, ...
|
|
|
|
Reg = SP::F1 + Offset/4;
|
|
|
|
|
|
|
|
// Promote to register when possible, otherwise use the stack slot.
|
|
|
|
if (Reg) {
|
|
|
|
State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This argument goes on the stack in an 8-byte slot.
|
|
|
|
// When passing floats, LocVT is smaller than 8 bytes. Adjust the offset to
|
|
|
|
// the right-aligned float. The first 4 bytes of the stack slot are undefined.
|
|
|
|
if (LocVT == MVT::f32)
|
|
|
|
Offset += 4;
|
|
|
|
|
|
|
|
State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allocate a half-sized argument for the 64-bit ABI.
|
|
|
|
//
|
|
|
|
// This is used when passing { float, int } structs by value in registers.
|
|
|
|
static bool CC_Sparc64_Half(unsigned &ValNo, MVT &ValVT,
|
|
|
|
MVT &LocVT, CCValAssign::LocInfo &LocInfo,
|
|
|
|
ISD::ArgFlagsTy &ArgFlags, CCState &State) {
|
|
|
|
assert(LocVT.getSizeInBits() == 32 && "Can't handle non-32 bits locations");
|
|
|
|
unsigned Offset = State.AllocateStack(4, 4);
|
|
|
|
|
|
|
|
if (LocVT == MVT::f32 && Offset < 16*8) {
|
|
|
|
// Promote floats to %f0-%f31.
|
|
|
|
State.addLoc(CCValAssign::getReg(ValNo, ValVT, SP::F0 + Offset/4,
|
|
|
|
LocVT, LocInfo));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (LocVT == MVT::i32 && Offset < 6*8) {
|
|
|
|
// Promote integers to %i0-%i5, using half the register.
|
|
|
|
unsigned Reg = SP::I0 + Offset/8;
|
|
|
|
LocVT = MVT::i64;
|
|
|
|
LocInfo = CCValAssign::AExt;
|
|
|
|
|
|
|
|
// Set the Custom bit if this i32 goes in the high bits of a register.
|
|
|
|
if (Offset % 8 == 0)
|
|
|
|
State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg,
|
|
|
|
LocVT, LocInfo));
|
|
|
|
else
|
|
|
|
State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-03-17 05:41:48 +00:00
|
|
|
#include "SparcGenCallingConv.inc"
|
2008-03-17 03:21:36 +00:00
|
|
|
|
2013-04-09 05:11:52 +00:00
|
|
|
// The calling conventions in SparcCallingConv.td are described in terms of the
|
|
|
|
// callee's register window. This function translates registers to the
|
|
|
|
// corresponding caller window %o register.
|
|
|
|
static unsigned toCallerWindow(unsigned Reg) {
|
|
|
|
assert(SP::I0 + 7 == SP::I7 && SP::O0 + 7 == SP::O7 && "Unexpected enum");
|
|
|
|
if (Reg >= SP::I0 && Reg <= SP::I7)
|
|
|
|
return Reg - SP::I0 + SP::O0;
|
|
|
|
return Reg;
|
|
|
|
}
|
|
|
|
|
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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78142 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-05 01:29:28 +00:00
|
|
|
SDValue
|
|
|
|
SparcTargetLowering::LowerReturn(SDValue Chain,
|
2013-04-06 23:57:33 +00: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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78142 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-05 01:29:28 +00:00
|
|
|
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
2010-07-07 15:54:55 +00:00
|
|
|
const SmallVectorImpl<SDValue> &OutVals,
|
2013-04-06 23:57:33 +00:00
|
|
|
DebugLoc DL, SelectionDAG &DAG) const {
|
|
|
|
if (Subtarget->is64Bit())
|
|
|
|
return LowerReturn_64(Chain, CallConv, IsVarArg, Outs, OutVals, DL, DAG);
|
|
|
|
return LowerReturn_32(Chain, CallConv, IsVarArg, Outs, OutVals, DL, DAG);
|
|
|
|
}
|
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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78142 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-05 01:29:28 +00:00
|
|
|
|
2013-04-06 23:57:33 +00:00
|
|
|
SDValue
|
|
|
|
SparcTargetLowering::LowerReturn_32(SDValue Chain,
|
|
|
|
CallingConv::ID CallConv, bool IsVarArg,
|
|
|
|
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
|
|
|
const SmallVectorImpl<SDValue> &OutVals,
|
|
|
|
DebugLoc DL, SelectionDAG &DAG) const {
|
2011-01-22 13:05:16 +00:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
|
2008-03-17 05:41:48 +00:00
|
|
|
// CCValAssign - represent the assignment of the return value to locations.
|
|
|
|
SmallVector<CCValAssign, 16> RVLocs;
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 05:41:48 +00:00
|
|
|
// CCState - Info about the registers and stack slot.
|
2013-04-06 23:57:33 +00:00
|
|
|
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(),
|
2012-07-19 00:11:40 +00:00
|
|
|
DAG.getTarget(), RVLocs, *DAG.getContext());
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2013-04-06 23:57:33 +00:00
|
|
|
// Analyze return values.
|
|
|
|
CCInfo.AnalyzeReturn(Outs, RetCC_Sparc32);
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Flag;
|
2013-02-05 18:16:58 +00:00
|
|
|
SmallVector<SDValue, 4> RetOps(1, Chain);
|
|
|
|
// Make room for the return address offset.
|
|
|
|
RetOps.push_back(SDValue());
|
2008-03-17 03:21:36 +00:00
|
|
|
|
2008-03-17 05:41:48 +00: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-10 20:27:31 +00:00
|
|
|
|
2013-04-06 23:57:33 +00:00
|
|
|
Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(),
|
2010-07-07 15:54:55 +00:00
|
|
|
OutVals[i], Flag);
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 05:41:48 +00:00
|
|
|
// Guarantee that all emitted copies are stuck together with flags.
|
|
|
|
Flag = Chain.getValue(1);
|
2013-02-05 18:16:58 +00:00
|
|
|
RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
|
2008-03-17 03:21:36 +00:00
|
|
|
}
|
2011-02-21 03:42:44 +00:00
|
|
|
|
|
|
|
unsigned RetAddrOffset = 8; //Call Inst + Delay Slot
|
2011-01-22 13:05:16 +00: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");
|
2013-04-06 23:57:33 +00:00
|
|
|
SDValue Val = DAG.getCopyFromReg(Chain, DL, Reg, getPointerTy());
|
|
|
|
Chain = DAG.getCopyToReg(Chain, DL, SP::I0, Val, Flag);
|
2011-01-22 13:05:16 +00:00
|
|
|
Flag = Chain.getValue(1);
|
2013-02-05 18:16:58 +00:00
|
|
|
RetOps.push_back(DAG.getRegister(SP::I0, getPointerTy()));
|
2011-02-21 03:42:44 +00:00
|
|
|
RetAddrOffset = 12; // CallInst + Delay Slot + Unimp
|
2011-01-22 13:05:16 +00:00
|
|
|
}
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2013-02-05 18:16:58 +00:00
|
|
|
RetOps[0] = Chain; // Update chain.
|
|
|
|
RetOps[1] = DAG.getConstant(RetAddrOffset, MVT::i32);
|
2011-02-21 03:42:44 +00:00
|
|
|
|
2013-02-05 18:16:58 +00:00
|
|
|
// Add the flag if we have it.
|
2008-08-28 21:40:38 +00:00
|
|
|
if (Flag.getNode())
|
2013-02-05 18:16:58 +00:00
|
|
|
RetOps.push_back(Flag);
|
|
|
|
|
2013-04-06 23:57:33 +00:00
|
|
|
return DAG.getNode(SPISD::RET_FLAG, DL, MVT::Other,
|
|
|
|
&RetOps[0], RetOps.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lower return values for the 64-bit ABI.
|
|
|
|
// Return values are passed the exactly the same way as function arguments.
|
|
|
|
SDValue
|
|
|
|
SparcTargetLowering::LowerReturn_64(SDValue Chain,
|
|
|
|
CallingConv::ID CallConv, bool IsVarArg,
|
|
|
|
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
|
|
|
const SmallVectorImpl<SDValue> &OutVals,
|
|
|
|
DebugLoc DL, SelectionDAG &DAG) const {
|
|
|
|
// CCValAssign - represent the assignment of the return value to locations.
|
|
|
|
SmallVector<CCValAssign, 16> RVLocs;
|
|
|
|
|
|
|
|
// CCState - Info about the registers and stack slot.
|
|
|
|
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(),
|
|
|
|
DAG.getTarget(), RVLocs, *DAG.getContext());
|
|
|
|
|
|
|
|
// Analyze return values.
|
|
|
|
CCInfo.AnalyzeReturn(Outs, CC_Sparc64);
|
|
|
|
|
|
|
|
SDValue Flag;
|
|
|
|
SmallVector<SDValue, 4> RetOps(1, Chain);
|
|
|
|
|
|
|
|
// The second operand on the return instruction is the return address offset.
|
|
|
|
// The return address is always %i7+8 with the 64-bit ABI.
|
|
|
|
RetOps.push_back(DAG.getConstant(8, MVT::i32));
|
|
|
|
|
|
|
|
// 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!");
|
|
|
|
SDValue OutVal = OutVals[i];
|
|
|
|
|
|
|
|
// Integer return values must be sign or zero extended by the callee.
|
|
|
|
switch (VA.getLocInfo()) {
|
|
|
|
case CCValAssign::SExt:
|
|
|
|
OutVal = DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), OutVal);
|
|
|
|
break;
|
|
|
|
case CCValAssign::ZExt:
|
|
|
|
OutVal = DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), OutVal);
|
|
|
|
break;
|
|
|
|
case CCValAssign::AExt:
|
|
|
|
OutVal = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), OutVal);
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The custom bit on an i32 return value indicates that it should be passed
|
|
|
|
// in the high bits of the register.
|
|
|
|
if (VA.getValVT() == MVT::i32 && VA.needsCustom()) {
|
|
|
|
OutVal = DAG.getNode(ISD::SHL, DL, MVT::i64, OutVal,
|
|
|
|
DAG.getConstant(32, MVT::i32));
|
|
|
|
|
|
|
|
// The next value may go in the low bits of the same register.
|
|
|
|
// Handle both at once.
|
|
|
|
if (i+1 < RVLocs.size() && RVLocs[i+1].getLocReg() == VA.getLocReg()) {
|
|
|
|
SDValue NV = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, OutVals[i+1]);
|
|
|
|
OutVal = DAG.getNode(ISD::OR, DL, MVT::i64, OutVal, NV);
|
|
|
|
// Skip the next value, it's already done.
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), OutVal, Flag);
|
|
|
|
|
|
|
|
// Guarantee that all emitted copies are stuck together with flags.
|
|
|
|
Flag = Chain.getValue(1);
|
|
|
|
RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
|
|
|
|
}
|
|
|
|
|
|
|
|
RetOps[0] = Chain; // Update chain.
|
|
|
|
|
|
|
|
// Add the flag if we have it.
|
|
|
|
if (Flag.getNode())
|
|
|
|
RetOps.push_back(Flag);
|
|
|
|
|
|
|
|
return DAG.getNode(SPISD::RET_FLAG, DL, MVT::Other,
|
2013-02-05 18:16:58 +00:00
|
|
|
&RetOps[0], RetOps.size());
|
2008-03-17 03:21:36 +00:00
|
|
|
}
|
|
|
|
|
2013-04-02 04:09:02 +00:00
|
|
|
SDValue SparcTargetLowering::
|
|
|
|
LowerFormalArguments(SDValue Chain,
|
|
|
|
CallingConv::ID CallConv,
|
|
|
|
bool IsVarArg,
|
|
|
|
const SmallVectorImpl<ISD::InputArg> &Ins,
|
|
|
|
DebugLoc DL,
|
|
|
|
SelectionDAG &DAG,
|
|
|
|
SmallVectorImpl<SDValue> &InVals) const {
|
|
|
|
if (Subtarget->is64Bit())
|
|
|
|
return LowerFormalArguments_64(Chain, CallConv, IsVarArg, Ins,
|
|
|
|
DL, DAG, InVals);
|
|
|
|
return LowerFormalArguments_32(Chain, CallConv, IsVarArg, Ins,
|
|
|
|
DL, DAG, InVals);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// LowerFormalArguments32 - V8 uses a very simple ABI, where all values are
|
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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78142 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-05 01:29:28 +00:00
|
|
|
/// passed in either one or two GPRs, including FP values. TODO: we should
|
|
|
|
/// pass FP values in FP registers for fastcc functions.
|
2013-04-02 04:09:02 +00:00
|
|
|
SDValue SparcTargetLowering::
|
|
|
|
LowerFormalArguments_32(SDValue Chain,
|
|
|
|
CallingConv::ID CallConv,
|
|
|
|
bool isVarArg,
|
|
|
|
const SmallVectorImpl<ISD::InputArg> &Ins,
|
|
|
|
DebugLoc dl,
|
|
|
|
SelectionDAG &DAG,
|
|
|
|
SmallVectorImpl<SDValue> &InVals) const {
|
2008-03-17 03:21:36 +00:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
MachineRegisterInfo &RegInfo = MF.getRegInfo();
|
2010-04-17 14:41:14 +00:00
|
|
|
SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
|
2009-07-19 19:53:46 +00:00
|
|
|
|
|
|
|
// Assign locations to all of the incoming arguments.
|
|
|
|
SmallVector<CCValAssign, 16> ArgLocs;
|
2011-06-08 23:55:35 +00:00
|
|
|
CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(),
|
2012-07-19 00:11:40 +00:00
|
|
|
getTargetMachine(), 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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78142 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-05 01:29:28 +00:00
|
|
|
CCInfo.AnalyzeFormalArguments(Ins, CC_Sparc32);
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2011-01-18 06:09:55 +00:00
|
|
|
const unsigned StackOffset = 92;
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2009-07-19 19:53:46 +00:00
|
|
|
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
|
|
|
CCValAssign &VA = ArgLocs[i];
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2011-01-22 13:05:16 +00: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(),
|
2011-11-08 18:42:53 +00:00
|
|
|
false, false, false, 0);
|
2011-01-22 13:05:16 +00:00
|
|
|
InVals.push_back(Arg);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-01-18 06:09:55 +00: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 03:21:36 +00:00
|
|
|
|
2011-01-18 06:09:55 +00:00
|
|
|
assert(i+1 < e);
|
|
|
|
CCValAssign &NextVA = ArgLocs[++i];
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue LoVal;
|
2011-01-18 06:09:55 +00:00
|
|
|
if (NextVA.isMemLoc()) {
|
|
|
|
int FrameIdx = MF.getFrameInfo()->
|
|
|
|
CreateFixedObject(4, StackOffset+NextVA.getLocMemOffset(),true);
|
2009-08-11 20:47:22 +00:00
|
|
|
SDValue FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32);
|
2011-01-18 06:09:55 +00:00
|
|
|
LoVal = DAG.getLoad(MVT::i32, dl, Chain, FIPtr,
|
|
|
|
MachinePointerInfo(),
|
2011-11-08 18:42:53 +00:00
|
|
|
false, false, false, 0);
|
2011-01-18 06:09:55 +00:00
|
|
|
} else {
|
|
|
|
unsigned loReg = MF.addLiveIn(NextVA.getLocReg(),
|
2011-02-21 23:21:26 +00:00
|
|
|
&SP::IntRegsRegClass);
|
2011-01-18 06:09:55 +00:00
|
|
|
LoVal = DAG.getCopyFromReg(Chain, dl, loReg, MVT::i32);
|
2008-03-17 03:21:36 +00:00
|
|
|
}
|
2008-10-10 20:27:31 +00:00
|
|
|
SDValue WholeValue =
|
2009-08-11 20:47:22 +00:00
|
|
|
DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, LoVal, HiVal);
|
2011-01-18 06:09:55 +00: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-10 20:27:31 +00:00
|
|
|
|
2011-01-18 06:09:55 +00:00
|
|
|
assert(VA.isMemLoc());
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2011-01-18 06:09:55 +00: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(),
|
2011-11-08 18:42:53 +00:00
|
|
|
false,false, false, 0);
|
2011-01-18 06:09:55 +00:00
|
|
|
InVals.push_back(Load);
|
|
|
|
continue;
|
2008-03-17 03:21:36 +00:00
|
|
|
}
|
2011-01-18 06:09:55 +00: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(),
|
2011-11-08 18:42:53 +00:00
|
|
|
false, false, false, 0);
|
2011-01-18 06:09:55 +00:00
|
|
|
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(),
|
2011-11-08 18:42:53 +00:00
|
|
|
false, false, false, 0);
|
2011-01-18 06:09:55 +00:00
|
|
|
|
|
|
|
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 03:21:36 +00:00
|
|
|
}
|
2011-01-18 06:09:55 +00: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(),
|
2011-11-08 18:42:53 +00:00
|
|
|
false, false, false, 0);
|
2011-01-18 06:09:55 +00:00
|
|
|
} 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-16 16:23:55 +00:00
|
|
|
Load = DAG.getExtLoad(LoadOp, dl, MVT::i32, Chain, FIPtr,
|
2011-01-18 06:09:55 +00:00
|
|
|
MachinePointerInfo(),
|
|
|
|
VA.getValVT(), false, false,0);
|
|
|
|
Load = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), Load);
|
|
|
|
}
|
|
|
|
InVals.push_back(Load);
|
2008-03-17 03:21:36 +00:00
|
|
|
}
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2011-01-22 13:05:16 +00: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 03:21:36 +00:00
|
|
|
// Store remaining ArgRegs to the stack if this is a varargs function.
|
2009-07-19 19:53:46 +00:00
|
|
|
if (isVarArg) {
|
2012-03-11 07:57:25 +00:00
|
|
|
static const uint16_t ArgRegs[] = {
|
2011-01-18 06:09:55 +00:00
|
|
|
SP::I0, SP::I1, SP::I2, SP::I3, SP::I4, SP::I5
|
|
|
|
};
|
|
|
|
unsigned NumAllocated = CCInfo.getFirstUnallocated(ArgRegs, 6);
|
2012-03-11 07:57:25 +00:00
|
|
|
const uint16_t *CurArgReg = ArgRegs+NumAllocated, *ArgRegEnd = ArgRegs+6;
|
2011-01-18 06:09:55 +00:00
|
|
|
unsigned ArgOffset = CCInfo.getNextStackOffset();
|
|
|
|
if (NumAllocated == 6)
|
|
|
|
ArgOffset += StackOffset;
|
|
|
|
else {
|
|
|
|
assert(!ArgOffset);
|
|
|
|
ArgOffset = 68+4*NumAllocated;
|
|
|
|
}
|
|
|
|
|
2008-03-17 03:21:36 +00:00
|
|
|
// Remember the vararg offset for the va_start implementation.
|
2010-04-17 14:41:14 +00:00
|
|
|
FuncInfo->setVarArgsFrameOffset(ArgOffset);
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2009-07-19 19:53:46 +00:00
|
|
|
std::vector<SDValue> OutChains;
|
|
|
|
|
2008-03-17 03:21:36 +00:00
|
|
|
for (; CurArgReg != ArgRegEnd; ++CurArgReg) {
|
|
|
|
unsigned VReg = RegInfo.createVirtualRegister(&SP::IntRegsRegClass);
|
|
|
|
MF.getRegInfo().addLiveIn(*CurArgReg, VReg);
|
2009-08-11 20:47:22 +00:00
|
|
|
SDValue Arg = DAG.getCopyFromReg(DAG.getRoot(), dl, VReg, MVT::i32);
|
2008-03-17 03:21:36 +00:00
|
|
|
|
2009-11-12 20:49:22 +00:00
|
|
|
int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, ArgOffset,
|
2010-07-03 00:40:23 +00:00
|
|
|
true);
|
2009-08-11 20:47:22 +00:00
|
|
|
SDValue FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32);
|
2008-03-17 03:21:36 +00:00
|
|
|
|
2010-09-21 18:41:36 +00:00
|
|
|
OutChains.push_back(DAG.getStore(DAG.getRoot(), dl, Arg, FIPtr,
|
|
|
|
MachinePointerInfo(),
|
2010-02-15 16:57:02 +00:00
|
|
|
false, false, 0));
|
2008-03-17 03:21:36 +00:00
|
|
|
ArgOffset += 4;
|
|
|
|
}
|
2009-07-19 19:53:46 +00: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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78142 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-05 01:29:28 +00:00
|
|
|
OutChains.push_back(Chain);
|
2009-08-11 20:47:22 +00: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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78142 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-05 01:29:28 +00:00
|
|
|
&OutChains[0], OutChains.size());
|
2009-07-19 19:53:46 +00:00
|
|
|
}
|
2008-03-17 03:21:36 +00:00
|
|
|
}
|
2008-10-10 20:27:31 +00: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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78142 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-05 01:29:28 +00:00
|
|
|
return Chain;
|
2008-03-17 03:21:36 +00:00
|
|
|
}
|
|
|
|
|
2013-04-02 04:09:02 +00:00
|
|
|
// Lower formal arguments for the 64 bit ABI.
|
|
|
|
SDValue SparcTargetLowering::
|
|
|
|
LowerFormalArguments_64(SDValue Chain,
|
|
|
|
CallingConv::ID CallConv,
|
|
|
|
bool IsVarArg,
|
|
|
|
const SmallVectorImpl<ISD::InputArg> &Ins,
|
|
|
|
DebugLoc DL,
|
|
|
|
SelectionDAG &DAG,
|
|
|
|
SmallVectorImpl<SDValue> &InVals) const {
|
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
|
|
|
|
// Analyze arguments according to CC_Sparc64.
|
|
|
|
SmallVector<CCValAssign, 16> ArgLocs;
|
|
|
|
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(),
|
|
|
|
getTargetMachine(), ArgLocs, *DAG.getContext());
|
|
|
|
CCInfo.AnalyzeFormalArguments(Ins, CC_Sparc64);
|
|
|
|
|
2013-04-20 22:49:16 +00:00
|
|
|
// The argument array begins at %fp+BIAS+128, after the register save area.
|
|
|
|
const unsigned ArgArea = 128;
|
|
|
|
|
2013-04-02 04:09:02 +00:00
|
|
|
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
|
|
|
CCValAssign &VA = ArgLocs[i];
|
|
|
|
if (VA.isRegLoc()) {
|
|
|
|
// This argument is passed in a register.
|
|
|
|
// All integer register arguments are promoted by the caller to i64.
|
|
|
|
|
|
|
|
// Create a virtual register for the promoted live-in value.
|
|
|
|
unsigned VReg = MF.addLiveIn(VA.getLocReg(),
|
|
|
|
getRegClassFor(VA.getLocVT()));
|
|
|
|
SDValue Arg = DAG.getCopyFromReg(Chain, DL, VReg, VA.getLocVT());
|
|
|
|
|
2013-04-06 18:32:12 +00:00
|
|
|
// Get the high bits for i32 struct elements.
|
|
|
|
if (VA.getValVT() == MVT::i32 && VA.needsCustom())
|
|
|
|
Arg = DAG.getNode(ISD::SRL, DL, VA.getLocVT(), Arg,
|
|
|
|
DAG.getConstant(32, MVT::i32));
|
|
|
|
|
2013-04-02 04:09:02 +00:00
|
|
|
// The caller promoted the argument, so insert an Assert?ext SDNode so we
|
|
|
|
// won't promote the value again in this function.
|
|
|
|
switch (VA.getLocInfo()) {
|
|
|
|
case CCValAssign::SExt:
|
|
|
|
Arg = DAG.getNode(ISD::AssertSext, DL, VA.getLocVT(), Arg,
|
|
|
|
DAG.getValueType(VA.getValVT()));
|
|
|
|
break;
|
|
|
|
case CCValAssign::ZExt:
|
|
|
|
Arg = DAG.getNode(ISD::AssertZext, DL, VA.getLocVT(), Arg,
|
|
|
|
DAG.getValueType(VA.getValVT()));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Truncate the register down to the argument type.
|
|
|
|
if (VA.isExtInLoc())
|
|
|
|
Arg = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), Arg);
|
|
|
|
|
|
|
|
InVals.push_back(Arg);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The registers are exhausted. This argument was passed on the stack.
|
|
|
|
assert(VA.isMemLoc());
|
2013-04-06 18:32:12 +00:00
|
|
|
// The CC_Sparc64_Full/Half functions compute stack offsets relative to the
|
|
|
|
// beginning of the arguments area at %fp+BIAS+128.
|
2013-04-20 22:49:16 +00:00
|
|
|
unsigned Offset = VA.getLocMemOffset() + ArgArea;
|
2013-04-06 18:32:12 +00:00
|
|
|
unsigned ValSize = VA.getValVT().getSizeInBits() / 8;
|
|
|
|
// Adjust offset for extended arguments, SPARC is big-endian.
|
|
|
|
// The caller will have written the full slot with extended bytes, but we
|
|
|
|
// prefer our own extending loads.
|
|
|
|
if (VA.isExtInLoc())
|
|
|
|
Offset += 8 - ValSize;
|
|
|
|
int FI = MF.getFrameInfo()->CreateFixedObject(ValSize, Offset, true);
|
|
|
|
InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain,
|
|
|
|
DAG.getFrameIndex(FI, getPointerTy()),
|
|
|
|
MachinePointerInfo::getFixedStack(FI),
|
|
|
|
false, false, false, 0));
|
2013-04-02 04:09:02 +00:00
|
|
|
}
|
2013-04-20 22:49:16 +00:00
|
|
|
|
|
|
|
if (!IsVarArg)
|
|
|
|
return Chain;
|
|
|
|
|
|
|
|
// This function takes variable arguments, some of which may have been passed
|
|
|
|
// in registers %i0-%i5. Variable floating point arguments are never passed
|
|
|
|
// in floating point registers. They go on %i0-%i5 or on the stack like
|
|
|
|
// integer arguments.
|
|
|
|
//
|
|
|
|
// The va_start intrinsic needs to know the offset to the first variable
|
|
|
|
// argument.
|
|
|
|
unsigned ArgOffset = CCInfo.getNextStackOffset();
|
|
|
|
SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
|
|
|
|
// Skip the 128 bytes of register save area.
|
|
|
|
FuncInfo->setVarArgsFrameOffset(ArgOffset + ArgArea +
|
|
|
|
Subtarget->getStackPointerBias());
|
|
|
|
|
|
|
|
// Save the variable arguments that were passed in registers.
|
|
|
|
// The caller is required to reserve stack space for 6 arguments regardless
|
|
|
|
// of how many arguments were actually passed.
|
|
|
|
SmallVector<SDValue, 8> OutChains;
|
|
|
|
for (; ArgOffset < 6*8; ArgOffset += 8) {
|
|
|
|
unsigned VReg = MF.addLiveIn(SP::I0 + ArgOffset/8, &SP::I64RegsRegClass);
|
|
|
|
SDValue VArg = DAG.getCopyFromReg(Chain, DL, VReg, MVT::i64);
|
|
|
|
int FI = MF.getFrameInfo()->CreateFixedObject(8, ArgOffset + ArgArea, true);
|
|
|
|
OutChains.push_back(DAG.getStore(Chain, DL, VArg,
|
|
|
|
DAG.getFrameIndex(FI, getPointerTy()),
|
|
|
|
MachinePointerInfo::getFixedStack(FI),
|
|
|
|
false, false, 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!OutChains.empty())
|
|
|
|
Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other,
|
|
|
|
&OutChains[0], OutChains.size());
|
|
|
|
|
2013-04-02 04:09:02 +00:00
|
|
|
return Chain;
|
|
|
|
}
|
|
|
|
|
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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78142 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-05 01:29:28 +00:00
|
|
|
SDValue
|
2012-05-25 16:35:28 +00:00
|
|
|
SparcTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
|
2010-04-17 15:26:15 +00:00
|
|
|
SmallVectorImpl<SDValue> &InVals) const {
|
2013-04-07 19:10:57 +00:00
|
|
|
if (Subtarget->is64Bit())
|
|
|
|
return LowerCall_64(CLI, InVals);
|
|
|
|
return LowerCall_32(CLI, InVals);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lower a call for the 32-bit ABI.
|
|
|
|
SDValue
|
|
|
|
SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI,
|
|
|
|
SmallVectorImpl<SDValue> &InVals) const {
|
2012-05-25 16:35:28 +00:00
|
|
|
SelectionDAG &DAG = CLI.DAG;
|
|
|
|
DebugLoc &dl = CLI.DL;
|
|
|
|
SmallVector<ISD::OutputArg, 32> &Outs = CLI.Outs;
|
|
|
|
SmallVector<SDValue, 32> &OutVals = CLI.OutVals;
|
|
|
|
SmallVector<ISD::InputArg, 32> &Ins = CLI.Ins;
|
|
|
|
SDValue Chain = CLI.Chain;
|
|
|
|
SDValue Callee = CLI.Callee;
|
|
|
|
bool &isTailCall = CLI.IsTailCall;
|
|
|
|
CallingConv::ID CallConv = CLI.CallConv;
|
|
|
|
bool isVarArg = CLI.IsVarArg;
|
|
|
|
|
2010-01-27 00:07:07 +00:00
|
|
|
// Sparc target does not yet support tail call optimization.
|
|
|
|
isTailCall = false;
|
2008-03-17 06:01:07 +00:00
|
|
|
|
2008-03-17 06:58:37 +00:00
|
|
|
// Analyze operands of the call, assigning locations to each operand.
|
|
|
|
SmallVector<CCValAssign, 16> ArgLocs;
|
2011-06-08 23:55:35 +00:00
|
|
|
CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(),
|
2012-07-19 00:11:40 +00:00
|
|
|
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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78142 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-05 01:29:28 +00:00
|
|
|
CCInfo.AnalyzeCallOperands(Outs, CC_Sparc32);
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 06:58:37 +00:00
|
|
|
// Get the size of the outgoing arguments stack space requirement.
|
|
|
|
unsigned ArgsSize = CCInfo.getNextStackOffset();
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 03:21:36 +00:00
|
|
|
// Keep stack frames 8-byte aligned.
|
|
|
|
ArgsSize = (ArgsSize+7) & ~7;
|
|
|
|
|
2011-01-21 14:00:01 +00: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-11 22:08:30 +00:00
|
|
|
Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(ArgsSize, true));
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-07-27 21:46:04 +00:00
|
|
|
SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass;
|
|
|
|
SmallVector<SDValue, 8> MemOpChains;
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2011-01-18 06:09:55 +00:00
|
|
|
const unsigned StackOffset = 92;
|
2011-02-21 03:42:44 +00:00
|
|
|
bool hasStructRetAttr = false;
|
2008-03-17 06:58:37 +00:00
|
|
|
// Walk the register/memloc assignments, inserting copies/loads.
|
2011-01-21 14:00:01 +00:00
|
|
|
for (unsigned i = 0, realArgIdx = 0, byvalArgIdx = 0, e = ArgLocs.size();
|
2011-01-18 06:09:55 +00:00
|
|
|
i != e;
|
|
|
|
++i, ++realArgIdx) {
|
2008-03-17 06:58:37 +00:00
|
|
|
CCValAssign &VA = ArgLocs[i];
|
2011-01-18 06:09:55 +00:00
|
|
|
SDValue Arg = OutVals[realArgIdx];
|
2008-03-17 06:58:37 +00:00
|
|
|
|
2011-01-21 14:00:01 +00: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 06:58:37 +00:00
|
|
|
// Promote the value if needed.
|
|
|
|
switch (VA.getLocInfo()) {
|
2009-07-14 16:55:14 +00:00
|
|
|
default: llvm_unreachable("Unknown loc info!");
|
2008-03-17 06:58:37 +00:00
|
|
|
case CCValAssign::Full: break;
|
|
|
|
case CCValAssign::SExt:
|
2011-01-18 06:09:55 +00:00
|
|
|
Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg);
|
2008-03-17 06:58:37 +00:00
|
|
|
break;
|
|
|
|
case CCValAssign::ZExt:
|
2011-01-18 06:09:55 +00:00
|
|
|
Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg);
|
2008-03-17 06:58:37 +00:00
|
|
|
break;
|
|
|
|
case CCValAssign::AExt:
|
2011-01-18 06:09:55 +00: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 06:58:37 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2011-01-22 13:05:16 +00: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 03:42:44 +00:00
|
|
|
hasStructRetAttr = true;
|
2011-01-22 13:05:16 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-01-18 06:09:55 +00: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 05:37:15 +00:00
|
|
|
}
|
2008-12-12 08:05:40 +00:00
|
|
|
}
|
2011-01-18 06:09:55 +00:00
|
|
|
|
2009-08-11 20:47:22 +00:00
|
|
|
SDValue StackPtr = DAG.CreateStackTemporary(MVT::f64, MVT::i32);
|
2010-11-23 03:31:01 +00:00
|
|
|
SDValue Store = DAG.getStore(DAG.getEntryNode(), dl,
|
2011-01-18 06:09:55 +00:00
|
|
|
Arg, StackPtr, MachinePointerInfo(),
|
2010-02-15 16:57:02 +00:00
|
|
|
false, false, 0);
|
2008-12-12 08:05:40 +00:00
|
|
|
// Sparc is big-endian, so the high part comes first.
|
2010-09-21 06:44:06 +00:00
|
|
|
SDValue Hi = DAG.getLoad(MVT::i32, dl, Store, StackPtr,
|
2011-11-08 18:42:53 +00:00
|
|
|
MachinePointerInfo(), false, false, false, 0);
|
2008-12-12 08:05:40 +00:00
|
|
|
// Increment the pointer to the other half.
|
2009-02-04 20:06:27 +00:00
|
|
|
StackPtr = DAG.getNode(ISD::ADD, dl, StackPtr.getValueType(), StackPtr,
|
2008-12-12 08:05:40 +00:00
|
|
|
DAG.getIntPtrConstant(4));
|
|
|
|
// Load the low part.
|
2010-09-21 06:44:06 +00:00
|
|
|
SDValue Lo = DAG.getLoad(MVT::i32, dl, Store, StackPtr,
|
2011-11-08 18:42:53 +00:00
|
|
|
MachinePointerInfo(), false, false, false, 0);
|
2008-12-12 08:05:40 +00:00
|
|
|
|
2011-01-18 06:09:55 +00: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 08:05:40 +00:00
|
|
|
} else {
|
2011-01-18 06:09:55 +00: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 08:05:40 +00:00
|
|
|
}
|
2011-01-18 06:09:55 +00:00
|
|
|
continue;
|
2008-12-12 08:05:40 +00:00
|
|
|
}
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2011-01-18 06:09:55 +00: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 03:21:36 +00:00
|
|
|
}
|
2011-01-18 06:09:55 +00:00
|
|
|
Arg = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Arg);
|
|
|
|
RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
|
|
|
|
continue;
|
2008-12-12 08:05:40 +00:00
|
|
|
}
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2011-01-18 06:09:55 +00: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 03:21:36 +00:00
|
|
|
}
|
2011-01-18 06:09:55 +00:00
|
|
|
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 03:21:36 +00:00
|
|
|
// Emit all stores, make sure the occur before any copies into physregs.
|
2008-03-17 06:58:37 +00:00
|
|
|
if (!MemOpChains.empty())
|
2009-08-11 20:47:22 +00:00
|
|
|
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
|
2008-03-17 06:58:37 +00:00
|
|
|
&MemOpChains[0], MemOpChains.size());
|
2008-10-10 20:27:31 +00:00
|
|
|
|
|
|
|
// Build a sequence of copy-to-reg nodes chained together with token
|
2008-03-17 06:58:37 +00:00
|
|
|
// chain and flag operands which copy the outgoing args into registers.
|
2011-04-15 05:18:47 +00:00
|
|
|
// The InFlag in necessary since all emitted instructions must be
|
2008-03-17 06:58:37 +00:00
|
|
|
// stuck together.
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue InFlag;
|
2008-03-17 06:58:37 +00:00
|
|
|
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
|
2013-04-09 05:11:52 +00:00
|
|
|
unsigned Reg = toCallerWindow(RegsToPass[i].first);
|
2009-02-04 20:06:27 +00:00
|
|
|
Chain = DAG.getCopyToReg(Chain, dl, Reg, RegsToPass[i].second, InFlag);
|
2008-03-17 03:21:36 +00:00
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
}
|
|
|
|
|
2011-02-21 03:42:44 +00:00
|
|
|
unsigned SRetArgSize = (hasStructRetAttr)? getSRetArgSize(DAG, Callee):0;
|
|
|
|
|
2008-03-17 03:21:36 +00: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-16 21:48:12 +00:00
|
|
|
// Likewise ExternalSymbol -> TargetExternalSymbol.
|
2008-03-17 03:21:36 +00:00
|
|
|
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
|
2010-07-06 22:08:15 +00:00
|
|
|
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i32);
|
2008-09-16 21:48:12 +00:00
|
|
|
else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee))
|
2009-08-11 20:47:22 +00:00
|
|
|
Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32);
|
2008-03-17 03:21:36 +00:00
|
|
|
|
2011-01-12 03:18:21 +00: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 03:42:44 +00:00
|
|
|
if (hasStructRetAttr)
|
|
|
|
Ops.push_back(DAG.getTargetConstant(SRetArgSize, MVT::i32));
|
2013-04-09 05:11:52 +00:00
|
|
|
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i)
|
|
|
|
Ops.push_back(DAG.getRegister(toCallerWindow(RegsToPass[i].first),
|
|
|
|
RegsToPass[i].second.getValueType()));
|
2011-01-12 03:18:21 +00:00
|
|
|
if (InFlag.getNode())
|
|
|
|
Ops.push_back(InFlag);
|
|
|
|
|
|
|
|
Chain = DAG.getNode(SPISD::CALL, dl, NodeTys, &Ops[0], Ops.size());
|
2008-03-17 03:21:36 +00:00
|
|
|
InFlag = Chain.getValue(1);
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-10-11 22:08:30 +00:00
|
|
|
Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(ArgsSize, true),
|
|
|
|
DAG.getIntPtrConstant(0, true), InFlag);
|
2008-03-17 06:01:07 +00:00
|
|
|
InFlag = Chain.getValue(1);
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 06:01:07 +00:00
|
|
|
// Assign locations to each value returned by this call.
|
|
|
|
SmallVector<CCValAssign, 16> RVLocs;
|
2011-06-08 23:55:35 +00:00
|
|
|
CCState RVInfo(CallConv, isVarArg, DAG.getMachineFunction(),
|
2012-07-19 00:11:40 +00:00
|
|
|
DAG.getTarget(), RVLocs, *DAG.getContext());
|
2008-10-10 20:27:31 +00: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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78142 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-05 01:29:28 +00:00
|
|
|
RVInfo.AnalyzeCallResult(Ins, RetCC_Sparc32);
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 06:01:07 +00:00
|
|
|
// Copy all of the result registers out of their specified physreg.
|
|
|
|
for (unsigned i = 0; i != RVLocs.size(); ++i) {
|
2013-04-09 05:11:52 +00:00
|
|
|
Chain = DAG.getCopyFromReg(Chain, dl, toCallerWindow(RVLocs[i].getLocReg()),
|
2008-03-17 06:01:07 +00: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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78142 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-05 01:29:28 +00:00
|
|
|
InVals.push_back(Chain.getValue(0));
|
2008-03-17 03:21:36 +00:00
|
|
|
}
|
2008-10-10 20:27:31 +00: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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78142 91177308-0d34-0410-b5e6-96231b3b80d8
2009-08-05 01:29:28 +00:00
|
|
|
return Chain;
|
2008-03-17 03:21:36 +00:00
|
|
|
}
|
|
|
|
|
2011-02-21 03:42:44 +00: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 05:41:48 +00:00
|
|
|
|
2011-02-21 03:42:44 +00:00
|
|
|
assert(CalleeFn->hasStructRetAttr() &&
|
|
|
|
"Callee does not have the StructRet attribute.");
|
|
|
|
|
2011-07-18 04:54:35 +00:00
|
|
|
PointerType *Ty = cast<PointerType>(CalleeFn->arg_begin()->getType());
|
|
|
|
Type *ElementTy = Ty->getElementType();
|
2012-10-08 16:38:25 +00:00
|
|
|
return getDataLayout()->getTypeAllocSize(ElementTy);
|
2011-02-21 03:42:44 +00:00
|
|
|
}
|
2008-03-17 05:41:48 +00:00
|
|
|
|
2013-04-21 21:36:49 +00:00
|
|
|
|
|
|
|
// Fixup floating point arguments in the ... part of a varargs call.
|
|
|
|
//
|
|
|
|
// The SPARC v9 ABI requires that floating point arguments are treated the same
|
|
|
|
// as integers when calling a varargs function. This does not apply to the
|
|
|
|
// fixed arguments that are part of the function's prototype.
|
|
|
|
//
|
|
|
|
// This function post-processes a CCValAssign array created by
|
|
|
|
// AnalyzeCallOperands().
|
|
|
|
static void fixupVariableFloatArgs(SmallVectorImpl<CCValAssign> &ArgLocs,
|
|
|
|
ArrayRef<ISD::OutputArg> Outs) {
|
|
|
|
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
|
|
|
const CCValAssign &VA = ArgLocs[i];
|
|
|
|
// FIXME: What about f32 arguments? C promotes them to f64 when calling
|
|
|
|
// varargs functions.
|
|
|
|
if (!VA.isRegLoc() || VA.getLocVT() != MVT::f64)
|
|
|
|
continue;
|
|
|
|
// The fixed arguments to a varargs function still go in FP registers.
|
|
|
|
if (Outs[VA.getValNo()].IsFixed)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// This floating point argument should be reassigned.
|
|
|
|
CCValAssign NewVA;
|
|
|
|
|
|
|
|
// Determine the offset into the argument array.
|
|
|
|
unsigned Offset = 8 * (VA.getLocReg() - SP::D0);
|
|
|
|
assert(Offset < 16*8 && "Offset out of range, bad register enum?");
|
|
|
|
|
|
|
|
if (Offset < 6*8) {
|
|
|
|
// This argument should go in %i0-%i5.
|
|
|
|
unsigned IReg = SP::I0 + Offset/8;
|
|
|
|
// Full register, just bitconvert into i64.
|
|
|
|
NewVA = CCValAssign::getReg(VA.getValNo(), VA.getValVT(),
|
|
|
|
IReg, MVT::i64, CCValAssign::BCvt);
|
|
|
|
} else {
|
|
|
|
// This needs to go to memory, we're out of integer registers.
|
|
|
|
NewVA = CCValAssign::getMem(VA.getValNo(), VA.getValVT(),
|
|
|
|
Offset, VA.getLocVT(), VA.getLocInfo());
|
|
|
|
}
|
|
|
|
ArgLocs[i] = NewVA;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-07 19:10:57 +00:00
|
|
|
// Lower a call for the 64-bit ABI.
|
|
|
|
SDValue
|
|
|
|
SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI,
|
|
|
|
SmallVectorImpl<SDValue> &InVals) const {
|
|
|
|
SelectionDAG &DAG = CLI.DAG;
|
|
|
|
DebugLoc DL = CLI.DL;
|
|
|
|
SDValue Chain = CLI.Chain;
|
|
|
|
|
|
|
|
// Analyze operands of the call, assigning locations to each operand.
|
|
|
|
SmallVector<CCValAssign, 16> ArgLocs;
|
|
|
|
CCState CCInfo(CLI.CallConv, CLI.IsVarArg, DAG.getMachineFunction(),
|
|
|
|
DAG.getTarget(), ArgLocs, *DAG.getContext());
|
|
|
|
CCInfo.AnalyzeCallOperands(CLI.Outs, CC_Sparc64);
|
|
|
|
|
|
|
|
// Get the size of the outgoing arguments stack space requirement.
|
|
|
|
// The stack offset computed by CC_Sparc64 includes all arguments.
|
2013-04-09 04:37:47 +00:00
|
|
|
// Called functions expect 6 argument words to exist in the stack frame, used
|
|
|
|
// or not.
|
|
|
|
unsigned ArgsSize = std::max(6*8u, CCInfo.getNextStackOffset());
|
2013-04-07 19:10:57 +00:00
|
|
|
|
|
|
|
// Keep stack frames 16-byte aligned.
|
|
|
|
ArgsSize = RoundUpToAlignment(ArgsSize, 16);
|
|
|
|
|
2013-04-21 21:36:49 +00:00
|
|
|
// Varargs calls require special treatment.
|
|
|
|
if (CLI.IsVarArg)
|
|
|
|
fixupVariableFloatArgs(ArgLocs, CLI.Outs);
|
|
|
|
|
2013-04-07 19:10:57 +00:00
|
|
|
// Adjust the stack pointer to make room for the arguments.
|
|
|
|
// FIXME: Use hasReservedCallFrame to avoid %sp adjustments around all calls
|
|
|
|
// with more than 6 arguments.
|
|
|
|
Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(ArgsSize, true));
|
|
|
|
|
|
|
|
// Collect the set of registers to pass to the function and their values.
|
|
|
|
// This will be emitted as a sequence of CopyToReg nodes glued to the call
|
|
|
|
// instruction.
|
|
|
|
SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass;
|
|
|
|
|
|
|
|
// Collect chains from all the memory opeations that copy arguments to the
|
|
|
|
// stack. They must follow the stack pointer adjustment above and precede the
|
|
|
|
// call instruction itself.
|
|
|
|
SmallVector<SDValue, 8> MemOpChains;
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
|
|
|
const CCValAssign &VA = ArgLocs[i];
|
|
|
|
SDValue Arg = CLI.OutVals[i];
|
|
|
|
|
|
|
|
// Promote the value if needed.
|
|
|
|
switch (VA.getLocInfo()) {
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Unknown location info!");
|
|
|
|
case CCValAssign::Full:
|
|
|
|
break;
|
|
|
|
case CCValAssign::SExt:
|
|
|
|
Arg = DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), Arg);
|
|
|
|
break;
|
|
|
|
case CCValAssign::ZExt:
|
|
|
|
Arg = DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), Arg);
|
|
|
|
break;
|
|
|
|
case CCValAssign::AExt:
|
|
|
|
Arg = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Arg);
|
|
|
|
break;
|
|
|
|
case CCValAssign::BCvt:
|
|
|
|
Arg = DAG.getNode(ISD::BITCAST, DL, VA.getLocVT(), Arg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VA.isRegLoc()) {
|
|
|
|
// The custom bit on an i32 return value indicates that it should be
|
|
|
|
// passed in the high bits of the register.
|
|
|
|
if (VA.getValVT() == MVT::i32 && VA.needsCustom()) {
|
|
|
|
Arg = DAG.getNode(ISD::SHL, DL, MVT::i64, Arg,
|
|
|
|
DAG.getConstant(32, MVT::i32));
|
|
|
|
|
|
|
|
// The next value may go in the low bits of the same register.
|
|
|
|
// Handle both at once.
|
|
|
|
if (i+1 < ArgLocs.size() && ArgLocs[i+1].isRegLoc() &&
|
|
|
|
ArgLocs[i+1].getLocReg() == VA.getLocReg()) {
|
|
|
|
SDValue NV = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64,
|
|
|
|
CLI.OutVals[i+1]);
|
|
|
|
Arg = DAG.getNode(ISD::OR, DL, MVT::i64, Arg, NV);
|
|
|
|
// Skip the next value, it's already done.
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
2013-04-09 05:11:52 +00:00
|
|
|
RegsToPass.push_back(std::make_pair(toCallerWindow(VA.getLocReg()), Arg));
|
2013-04-07 19:10:57 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(VA.isMemLoc());
|
|
|
|
|
|
|
|
// Create a store off the stack pointer for this argument.
|
|
|
|
SDValue StackPtr = DAG.getRegister(SP::O6, getPointerTy());
|
|
|
|
// The argument area starts at %fp+BIAS+128 in the callee frame,
|
|
|
|
// %sp+BIAS+128 in ours.
|
|
|
|
SDValue PtrOff = DAG.getIntPtrConstant(VA.getLocMemOffset() +
|
|
|
|
Subtarget->getStackPointerBias() +
|
|
|
|
128);
|
|
|
|
PtrOff = DAG.getNode(ISD::ADD, DL, getPointerTy(), StackPtr, PtrOff);
|
|
|
|
MemOpChains.push_back(DAG.getStore(Chain, DL, Arg, PtrOff,
|
|
|
|
MachinePointerInfo(),
|
|
|
|
false, false, 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emit all stores, make sure they occur before the call.
|
|
|
|
if (!MemOpChains.empty())
|
|
|
|
Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other,
|
|
|
|
&MemOpChains[0], MemOpChains.size());
|
|
|
|
|
|
|
|
// Build a sequence of CopyToReg nodes glued together with token chain and
|
|
|
|
// glue operands which copy the outgoing args into registers. The InGlue is
|
|
|
|
// necessary since all emitted instructions must be stuck together in order
|
|
|
|
// to pass the live physical registers.
|
|
|
|
SDValue InGlue;
|
|
|
|
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
|
|
|
|
Chain = DAG.getCopyToReg(Chain, DL,
|
|
|
|
RegsToPass[i].first, RegsToPass[i].second, InGlue);
|
|
|
|
InGlue = Chain.getValue(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
// Likewise ExternalSymbol -> TargetExternalSymbol.
|
|
|
|
SDValue Callee = CLI.Callee;
|
|
|
|
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
|
|
|
|
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, getPointerTy());
|
|
|
|
else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee))
|
|
|
|
Callee = DAG.getTargetExternalSymbol(E->getSymbol(), getPointerTy());
|
|
|
|
|
|
|
|
// Build the operands for the call instruction itself.
|
|
|
|
SmallVector<SDValue, 8> Ops;
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(Callee);
|
|
|
|
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i)
|
|
|
|
Ops.push_back(DAG.getRegister(RegsToPass[i].first,
|
|
|
|
RegsToPass[i].second.getValueType()));
|
|
|
|
|
|
|
|
// Make sure the CopyToReg nodes are glued to the call instruction which
|
|
|
|
// consumes the registers.
|
|
|
|
if (InGlue.getNode())
|
|
|
|
Ops.push_back(InGlue);
|
|
|
|
|
|
|
|
// Now the call itself.
|
|
|
|
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
|
|
|
|
Chain = DAG.getNode(SPISD::CALL, DL, NodeTys, &Ops[0], Ops.size());
|
|
|
|
InGlue = Chain.getValue(1);
|
|
|
|
|
|
|
|
// Revert the stack pointer immediately after the call.
|
|
|
|
Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(ArgsSize, true),
|
|
|
|
DAG.getIntPtrConstant(0, true), InGlue);
|
|
|
|
InGlue = Chain.getValue(1);
|
|
|
|
|
|
|
|
// Now extract the return values. This is more or less the same as
|
|
|
|
// LowerFormalArguments_64.
|
|
|
|
|
|
|
|
// Assign locations to each value returned by this call.
|
|
|
|
SmallVector<CCValAssign, 16> RVLocs;
|
|
|
|
CCState RVInfo(CLI.CallConv, CLI.IsVarArg, DAG.getMachineFunction(),
|
|
|
|
DAG.getTarget(), RVLocs, *DAG.getContext());
|
|
|
|
RVInfo.AnalyzeCallResult(CLI.Ins, CC_Sparc64);
|
|
|
|
|
|
|
|
// Copy all of the result registers out of their specified physreg.
|
|
|
|
for (unsigned i = 0; i != RVLocs.size(); ++i) {
|
|
|
|
CCValAssign &VA = RVLocs[i];
|
2013-04-09 05:11:52 +00:00
|
|
|
unsigned Reg = toCallerWindow(VA.getLocReg());
|
2013-04-07 19:10:57 +00:00
|
|
|
|
|
|
|
// When returning 'inreg {i32, i32 }', two consecutive i32 arguments can
|
|
|
|
// reside in the same register in the high and low bits. Reuse the
|
|
|
|
// CopyFromReg previous node to avoid duplicate copies.
|
|
|
|
SDValue RV;
|
|
|
|
if (RegisterSDNode *SrcReg = dyn_cast<RegisterSDNode>(Chain.getOperand(1)))
|
|
|
|
if (SrcReg->getReg() == Reg && Chain->getOpcode() == ISD::CopyFromReg)
|
|
|
|
RV = Chain.getValue(0);
|
|
|
|
|
|
|
|
// But usually we'll create a new CopyFromReg for a different register.
|
|
|
|
if (!RV.getNode()) {
|
|
|
|
RV = DAG.getCopyFromReg(Chain, DL, Reg, RVLocs[i].getLocVT(), InGlue);
|
|
|
|
Chain = RV.getValue(1);
|
|
|
|
InGlue = Chain.getValue(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the high bits for i32 struct elements.
|
|
|
|
if (VA.getValVT() == MVT::i32 && VA.needsCustom())
|
|
|
|
RV = DAG.getNode(ISD::SRL, DL, VA.getLocVT(), RV,
|
|
|
|
DAG.getConstant(32, MVT::i32));
|
|
|
|
|
|
|
|
// The callee promoted the return value, so insert an Assert?ext SDNode so
|
|
|
|
// we won't promote the value again in this function.
|
|
|
|
switch (VA.getLocInfo()) {
|
|
|
|
case CCValAssign::SExt:
|
|
|
|
RV = DAG.getNode(ISD::AssertSext, DL, VA.getLocVT(), RV,
|
|
|
|
DAG.getValueType(VA.getValVT()));
|
|
|
|
break;
|
|
|
|
case CCValAssign::ZExt:
|
|
|
|
RV = DAG.getNode(ISD::AssertZext, DL, VA.getLocVT(), RV,
|
|
|
|
DAG.getValueType(VA.getValVT()));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Truncate the register down to the return value type.
|
|
|
|
if (VA.isExtInLoc())
|
|
|
|
RV = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), RV);
|
|
|
|
|
|
|
|
InVals.push_back(RV);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Chain;
|
|
|
|
}
|
|
|
|
|
2008-03-17 05:41:48 +00: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-14 16:55:14 +00:00
|
|
|
default: llvm_unreachable("Unknown integer condition code!");
|
2008-03-17 05:41:48 +00: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-14 16:55:14 +00:00
|
|
|
default: llvm_unreachable("Unknown fp condition code!");
|
2008-03-17 05:41:48 +00: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-08 20:43:12 +00:00
|
|
|
: TargetLowering(TM, new TargetLoweringObjectFileELF()) {
|
2013-04-02 04:08:54 +00:00
|
|
|
Subtarget = &TM.getSubtarget<SparcSubtarget>();
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 05:41:48 +00:00
|
|
|
// Set up the register classes.
|
2012-04-20 06:31:50 +00:00
|
|
|
addRegisterClass(MVT::i32, &SP::IntRegsRegClass);
|
|
|
|
addRegisterClass(MVT::f32, &SP::FPRegsRegClass);
|
|
|
|
addRegisterClass(MVT::f64, &SP::DFPRegsRegClass);
|
2013-04-02 04:08:54 +00:00
|
|
|
if (Subtarget->is64Bit())
|
|
|
|
addRegisterClass(MVT::i64, &SP::I64RegsRegClass);
|
2008-03-17 05:41:48 +00:00
|
|
|
|
|
|
|
// Turn FP extload into load/fextend
|
2009-08-11 20:47:22 +00:00
|
|
|
setLoadExtAction(ISD::EXTLOAD, MVT::f32, Expand);
|
2008-03-17 05:41:48 +00:00
|
|
|
// Sparc doesn't have i1 sign extending load
|
2009-08-11 20:47:22 +00:00
|
|
|
setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote);
|
2008-03-17 05:41:48 +00:00
|
|
|
// Turn FP truncstore into trunc + store.
|
2009-08-11 20:47:22 +00:00
|
|
|
setTruncStoreAction(MVT::f64, MVT::f32, Expand);
|
2008-03-17 05:41:48 +00:00
|
|
|
|
|
|
|
// Custom legalize GlobalAddress nodes into LO/HI parts.
|
2013-04-13 19:02:23 +00:00
|
|
|
setOperationAction(ISD::GlobalAddress, getPointerTy(), Custom);
|
|
|
|
setOperationAction(ISD::GlobalTLSAddress, getPointerTy(), Custom);
|
|
|
|
setOperationAction(ISD::ConstantPool, getPointerTy(), Custom);
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 05:41:48 +00:00
|
|
|
// Sparc doesn't have sext_inreg, replace them with shl/sra
|
2009-08-11 20:47:22 +00: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 05:41:48 +00:00
|
|
|
|
|
|
|
// Sparc has no REM or DIVREM operations.
|
2009-08-11 20:47:22 +00: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 05:41:48 +00:00
|
|
|
|
|
|
|
// Custom expand fp<->sint
|
2009-08-11 20:47:22 +00:00
|
|
|
setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom);
|
|
|
|
setOperationAction(ISD::SINT_TO_FP, MVT::i32, Custom);
|
2008-03-17 05:41:48 +00:00
|
|
|
|
|
|
|
// Expand fp<->uint
|
2009-08-11 20:47:22 +00:00
|
|
|
setOperationAction(ISD::FP_TO_UINT, MVT::i32, Expand);
|
|
|
|
setOperationAction(ISD::UINT_TO_FP, MVT::i32, Expand);
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2010-11-23 03:31:01 +00:00
|
|
|
setOperationAction(ISD::BITCAST, MVT::f32, Expand);
|
|
|
|
setOperationAction(ISD::BITCAST, MVT::i32, Expand);
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 05:41:48 +00:00
|
|
|
// Sparc has no select or setcc: expand to SELECT_CC.
|
2009-08-11 20:47:22 +00: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-10 20:27:31 +00:00
|
|
|
|
2008-03-17 05:41:48 +00:00
|
|
|
// Sparc doesn't have BRCOND either, it has BR_CC.
|
2009-08-11 20:47:22 +00: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-10 20:27:31 +00:00
|
|
|
|
2009-08-11 20:47:22 +00:00
|
|
|
setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
|
|
|
|
setOperationAction(ISD::SELECT_CC, MVT::f32, Custom);
|
|
|
|
setOperationAction(ISD::SELECT_CC, MVT::f64, Custom);
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2013-04-03 04:41:44 +00:00
|
|
|
if (Subtarget->is64Bit()) {
|
|
|
|
setOperationAction(ISD::BR_CC, MVT::i64, Custom);
|
2013-04-04 03:08:00 +00:00
|
|
|
setOperationAction(ISD::SELECT_CC, MVT::i64, Custom);
|
2013-04-03 04:41:44 +00:00
|
|
|
}
|
|
|
|
|
2011-07-27 22:21:52 +00:00
|
|
|
// FIXME: There are instructions available for ATOMIC_FENCE
|
|
|
|
// on SparcV8 and later.
|
|
|
|
setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Expand);
|
2009-08-11 20:47:22 +00:00
|
|
|
|
|
|
|
setOperationAction(ISD::FSIN , MVT::f64, Expand);
|
|
|
|
setOperationAction(ISD::FCOS , MVT::f64, Expand);
|
2013-01-29 02:32:37 +00:00
|
|
|
setOperationAction(ISD::FSINCOS, MVT::f64, Expand);
|
2009-08-11 20:47:22 +00:00
|
|
|
setOperationAction(ISD::FREM , MVT::f64, Expand);
|
2011-07-08 21:39:21 +00:00
|
|
|
setOperationAction(ISD::FMA , MVT::f64, Expand);
|
2009-08-11 20:47:22 +00:00
|
|
|
setOperationAction(ISD::FSIN , MVT::f32, Expand);
|
|
|
|
setOperationAction(ISD::FCOS , MVT::f32, Expand);
|
2013-01-29 02:32:37 +00:00
|
|
|
setOperationAction(ISD::FSINCOS, MVT::f32, Expand);
|
2009-08-11 20:47:22 +00:00
|
|
|
setOperationAction(ISD::FREM , MVT::f32, Expand);
|
2011-07-08 21:39:21 +00:00
|
|
|
setOperationAction(ISD::FMA , MVT::f32, Expand);
|
2009-08-11 20:47:22 +00:00
|
|
|
setOperationAction(ISD::CTPOP, MVT::i32, Expand);
|
|
|
|
setOperationAction(ISD::CTTZ , MVT::i32, Expand);
|
2011-12-13 01:56:10 +00:00
|
|
|
setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i32, Expand);
|
2009-08-11 20:47:22 +00:00
|
|
|
setOperationAction(ISD::CTLZ , MVT::i32, Expand);
|
2011-12-13 01:56:10 +00:00
|
|
|
setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i32, Expand);
|
2009-08-11 20:47:22 +00:00
|
|
|
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 05:41:48 +00:00
|
|
|
|
|
|
|
// FIXME: Sparc provides these multiplies, but we don't have them yet.
|
2009-08-11 20:47:22 +00:00
|
|
|
setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand);
|
|
|
|
setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand);
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2009-08-11 20:47:22 +00:00
|
|
|
setOperationAction(ISD::EH_LABEL, MVT::Other, Expand);
|
2008-03-17 05:41:48 +00:00
|
|
|
|
|
|
|
// VASTART needs to be custom lowered to use the VarArgsFrameIndex.
|
2009-08-11 20:47:22 +00:00
|
|
|
setOperationAction(ISD::VASTART , MVT::Other, Custom);
|
2008-03-17 05:41:48 +00:00
|
|
|
// VAARG needs to be lowered to not do unaligned accesses for doubles.
|
2009-08-11 20:47:22 +00:00
|
|
|
setOperationAction(ISD::VAARG , MVT::Other, Custom);
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 05:41:48 +00:00
|
|
|
// Use the default implementation.
|
2009-08-11 20:47:22 +00: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 05:41:48 +00:00
|
|
|
|
|
|
|
// No debug info support yet.
|
2009-08-11 20:47:22 +00:00
|
|
|
setOperationAction(ISD::EH_LABEL, MVT::Other, Expand);
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 05:41:48 +00:00
|
|
|
setStackPointerRegisterToSaveRestore(SP::O6);
|
|
|
|
|
|
|
|
if (TM.getSubtarget<SparcSubtarget>().isV9())
|
2009-08-11 20:47:22 +00:00
|
|
|
setOperationAction(ISD::CTPOP, MVT::i32, Legal);
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2011-05-06 20:34:06 +00:00
|
|
|
setMinFunctionAlignment(2);
|
|
|
|
|
2008-03-17 05:41:48 +00: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";
|
2013-04-03 04:41:44 +00:00
|
|
|
case SPISD::BRXCC: return "SPISD::BRXCC";
|
2008-03-17 05:41:48 +00:00
|
|
|
case SPISD::BRFCC: return "SPISD::BRFCC";
|
|
|
|
case SPISD::SELECT_ICC: return "SPISD::SELECT_ICC";
|
2013-04-04 03:08:00 +00:00
|
|
|
case SPISD::SELECT_XCC: return "SPISD::SELECT_XCC";
|
2008-03-17 05:41:48 +00:00
|
|
|
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 05:08:36 +00:00
|
|
|
case SPISD::GLOBAL_BASE_REG: return "SPISD::GLOBAL_BASE_REG";
|
2011-01-21 22:00:00 +00:00
|
|
|
case SPISD::FLUSHW: return "SPISD::FLUSHW";
|
2008-03-17 05:41:48 +00: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-27 21:46:04 +00:00
|
|
|
void SparcTargetLowering::computeMaskedBitsForTargetNode(const SDValue Op,
|
2008-10-10 20:27:31 +00:00
|
|
|
APInt &KnownZero,
|
2008-03-17 05:41:48 +00:00
|
|
|
APInt &KnownOne,
|
|
|
|
const SelectionDAG &DAG,
|
|
|
|
unsigned Depth) const {
|
|
|
|
APInt KnownZero2, KnownOne2;
|
2012-04-04 12:51:34 +00:00
|
|
|
KnownZero = KnownOne = APInt(KnownZero.getBitWidth(), 0);
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 05:41:48 +00:00
|
|
|
switch (Op.getOpcode()) {
|
|
|
|
default: break;
|
|
|
|
case SPISD::SELECT_ICC:
|
2013-04-04 03:08:00 +00:00
|
|
|
case SPISD::SELECT_XCC:
|
2008-03-17 05:41:48 +00:00
|
|
|
case SPISD::SELECT_FCC:
|
2012-04-04 12:51:34 +00:00
|
|
|
DAG.ComputeMaskedBits(Op.getOperand(1), KnownZero, KnownOne, Depth+1);
|
|
|
|
DAG.ComputeMaskedBits(Op.getOperand(0), KnownZero2, KnownOne2, Depth+1);
|
2008-10-10 20:27:31 +00: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 05:41:48 +00:00
|
|
|
// Only known if known in both the LHS and RHS.
|
|
|
|
KnownOne &= KnownOne2;
|
|
|
|
KnownZero &= KnownZero2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-17 03:21:36 +00: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-27 21:46:04 +00:00
|
|
|
static void LookThroughSetCC(SDValue &LHS, SDValue &RHS,
|
2008-03-17 03:21:36 +00:00
|
|
|
ISD::CondCode CC, unsigned &SPCC) {
|
2008-09-12 16:56:44 +00:00
|
|
|
if (isa<ConstantSDNode>(RHS) &&
|
2010-06-18 14:22:04 +00:00
|
|
|
cast<ConstantSDNode>(RHS)->isNullValue() &&
|
2008-10-10 20:27:31 +00:00
|
|
|
CC == ISD::SETNE &&
|
2013-04-04 03:08:00 +00:00
|
|
|
(((LHS.getOpcode() == SPISD::SELECT_ICC ||
|
|
|
|
LHS.getOpcode() == SPISD::SELECT_XCC) &&
|
2008-03-17 03:21:36 +00:00
|
|
|
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 14:22:04 +00:00
|
|
|
cast<ConstantSDNode>(LHS.getOperand(0))->isOne() &&
|
|
|
|
cast<ConstantSDNode>(LHS.getOperand(1))->isNullValue()) {
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue CMPCC = LHS.getOperand(3);
|
2008-09-12 16:56:44 +00:00
|
|
|
SPCC = cast<ConstantSDNode>(LHS.getOperand(2))->getZExtValue();
|
2008-03-17 03:21:36 +00:00
|
|
|
LHS = CMPCC.getOperand(0);
|
|
|
|
RHS = CMPCC.getOperand(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-14 01:33:32 +00:00
|
|
|
// Convert to a target node and set target flags.
|
|
|
|
SDValue SparcTargetLowering::withTargetFlags(SDValue Op, unsigned TF,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
if (const GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op))
|
|
|
|
return DAG.getTargetGlobalAddress(GA->getGlobal(),
|
|
|
|
GA->getDebugLoc(),
|
|
|
|
GA->getValueType(0),
|
|
|
|
GA->getOffset(), TF);
|
2013-04-14 04:35:16 +00:00
|
|
|
|
|
|
|
if (const ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(Op))
|
|
|
|
return DAG.getTargetConstantPool(CP->getConstVal(),
|
|
|
|
CP->getValueType(0),
|
|
|
|
CP->getAlignment(),
|
|
|
|
CP->getOffset(), TF);
|
|
|
|
|
|
|
|
if (const ExternalSymbolSDNode *ES = dyn_cast<ExternalSymbolSDNode>(Op))
|
|
|
|
return DAG.getTargetExternalSymbol(ES->getSymbol(),
|
|
|
|
ES->getValueType(0), TF);
|
|
|
|
|
2013-04-14 01:33:32 +00:00
|
|
|
llvm_unreachable("Unhandled address SDNode");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Split Op into high and low parts according to HiTF and LoTF.
|
|
|
|
// Return an ADD node combining the parts.
|
|
|
|
SDValue SparcTargetLowering::makeHiLoPair(SDValue Op,
|
|
|
|
unsigned HiTF, unsigned LoTF,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
DebugLoc DL = Op.getDebugLoc();
|
|
|
|
EVT VT = Op.getValueType();
|
|
|
|
SDValue Hi = DAG.getNode(SPISD::Hi, DL, VT, withTargetFlags(Op, HiTF, DAG));
|
|
|
|
SDValue Lo = DAG.getNode(SPISD::Lo, DL, VT, withTargetFlags(Op, LoTF, DAG));
|
|
|
|
return DAG.getNode(ISD::ADD, DL, VT, Hi, Lo);
|
|
|
|
}
|
|
|
|
|
2013-04-14 04:35:16 +00:00
|
|
|
// Build SDNodes for producing an address from a GlobalAddress, ConstantPool,
|
|
|
|
// or ExternalSymbol SDNode.
|
|
|
|
SDValue SparcTargetLowering::makeAddress(SDValue Op, SelectionDAG &DAG) const {
|
2013-04-14 04:57:51 +00:00
|
|
|
DebugLoc DL = Op.getDebugLoc();
|
|
|
|
EVT VT = getPointerTy();
|
|
|
|
|
2013-04-14 04:35:16 +00:00
|
|
|
// Handle PIC mode first.
|
|
|
|
if (getTargetMachine().getRelocationModel() == Reloc::PIC_) {
|
|
|
|
// This is the pic32 code model, the GOT is known to be smaller than 4GB.
|
|
|
|
SDValue HiLo = makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG);
|
|
|
|
SDValue GlobalBase = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, VT);
|
|
|
|
SDValue AbsAddr = DAG.getNode(ISD::ADD, DL, VT, GlobalBase, HiLo);
|
|
|
|
return DAG.getLoad(VT, DL, DAG.getEntryNode(), AbsAddr,
|
|
|
|
MachinePointerInfo::getGOT(), false, false, false, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is one of the absolute code models.
|
2013-04-14 04:57:51 +00:00
|
|
|
switch(getTargetMachine().getCodeModel()) {
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Unsupported absolute code model");
|
|
|
|
case CodeModel::Small:
|
2013-04-14 05:10:36 +00:00
|
|
|
// abs32.
|
2013-04-14 04:57:51 +00:00
|
|
|
return makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG);
|
|
|
|
case CodeModel::Medium: {
|
2013-04-14 05:10:36 +00:00
|
|
|
// abs44.
|
2013-04-14 04:57:51 +00:00
|
|
|
SDValue H44 = makeHiLoPair(Op, SPII::MO_H44, SPII::MO_M44, DAG);
|
2013-04-14 05:48:50 +00:00
|
|
|
H44 = DAG.getNode(ISD::SHL, DL, VT, H44, DAG.getConstant(12, MVT::i32));
|
2013-04-14 04:57:51 +00:00
|
|
|
SDValue L44 = withTargetFlags(Op, SPII::MO_L44, DAG);
|
|
|
|
L44 = DAG.getNode(SPISD::Lo, DL, VT, L44);
|
|
|
|
return DAG.getNode(ISD::ADD, DL, VT, H44, L44);
|
|
|
|
}
|
2013-04-14 05:10:36 +00:00
|
|
|
case CodeModel::Large: {
|
|
|
|
// abs64.
|
|
|
|
SDValue Hi = makeHiLoPair(Op, SPII::MO_HH, SPII::MO_HM, DAG);
|
2013-04-14 05:48:50 +00:00
|
|
|
Hi = DAG.getNode(ISD::SHL, DL, VT, Hi, DAG.getConstant(32, MVT::i32));
|
2013-04-14 05:10:36 +00:00
|
|
|
SDValue Lo = makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG);
|
|
|
|
return DAG.getNode(ISD::ADD, DL, VT, Hi, Lo);
|
|
|
|
}
|
2013-04-14 04:57:51 +00:00
|
|
|
}
|
2013-04-14 04:35:16 +00:00
|
|
|
}
|
|
|
|
|
2010-11-23 03:31:01 +00:00
|
|
|
SDValue SparcTargetLowering::LowerGlobalAddress(SDValue Op,
|
2010-04-17 15:26:15 +00:00
|
|
|
SelectionDAG &DAG) const {
|
2013-04-14 04:35:16 +00:00
|
|
|
return makeAddress(Op, DAG);
|
2008-03-17 03:21:36 +00:00
|
|
|
}
|
|
|
|
|
2009-09-15 17:46:24 +00:00
|
|
|
SDValue SparcTargetLowering::LowerConstantPool(SDValue Op,
|
2010-04-17 15:26:15 +00:00
|
|
|
SelectionDAG &DAG) const {
|
2013-04-14 04:35:16 +00:00
|
|
|
return makeAddress(Op, DAG);
|
2008-03-17 03:21:36 +00:00
|
|
|
}
|
|
|
|
|
2008-07-27 21:46:04 +00:00
|
|
|
static SDValue LowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG) {
|
2009-02-07 00:55:49 +00:00
|
|
|
DebugLoc dl = Op.getDebugLoc();
|
2008-03-17 03:21:36 +00:00
|
|
|
// Convert the fp value to integer in an FP register.
|
2009-08-11 20:47:22 +00:00
|
|
|
assert(Op.getValueType() == MVT::i32);
|
|
|
|
Op = DAG.getNode(SPISD::FTOI, dl, MVT::f32, Op.getOperand(0));
|
2010-11-23 03:31:01 +00:00
|
|
|
return DAG.getNode(ISD::BITCAST, dl, MVT::i32, Op);
|
2008-03-17 03:21:36 +00:00
|
|
|
}
|
|
|
|
|
2008-07-27 21:46:04 +00:00
|
|
|
static SDValue LowerSINT_TO_FP(SDValue Op, SelectionDAG &DAG) {
|
2009-02-07 00:55:49 +00:00
|
|
|
DebugLoc dl = Op.getDebugLoc();
|
2009-08-11 20:47:22 +00:00
|
|
|
assert(Op.getOperand(0).getValueType() == MVT::i32);
|
2010-11-23 03:31:01 +00:00
|
|
|
SDValue Tmp = DAG.getNode(ISD::BITCAST, dl, MVT::f32, Op.getOperand(0));
|
2008-03-17 03:21:36 +00:00
|
|
|
// Convert the int value to FP in an FP register.
|
2009-02-07 00:55:49 +00:00
|
|
|
return DAG.getNode(SPISD::ITOF, dl, Op.getValueType(), Tmp);
|
2008-03-17 03:21:36 +00:00
|
|
|
}
|
|
|
|
|
2008-07-27 21:46:04 +00:00
|
|
|
static SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) {
|
|
|
|
SDValue Chain = Op.getOperand(0);
|
2008-03-17 03:21:36 +00:00
|
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get();
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue LHS = Op.getOperand(2);
|
|
|
|
SDValue RHS = Op.getOperand(3);
|
|
|
|
SDValue Dest = Op.getOperand(4);
|
2009-02-05 22:07:54 +00:00
|
|
|
DebugLoc dl = Op.getDebugLoc();
|
2008-03-17 03:21:36 +00:00
|
|
|
unsigned Opc, SPCC = ~0U;
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 03:21:36 +00: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-10 20:27:31 +00:00
|
|
|
|
2008-03-17 03:21:36 +00:00
|
|
|
// Get the condition flag.
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue CompareFlag;
|
2013-04-03 04:41:44 +00:00
|
|
|
if (LHS.getValueType().isInteger()) {
|
|
|
|
EVT VTs[] = { LHS.getValueType(), MVT::Glue };
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Ops[2] = { LHS, RHS };
|
2009-02-05 22:07:54 +00:00
|
|
|
CompareFlag = DAG.getNode(SPISD::CMPICC, dl, VTs, Ops, 2).getValue(1);
|
2008-03-17 03:21:36 +00:00
|
|
|
if (SPCC == ~0U) SPCC = IntCondCCodeToICC(CC);
|
2013-04-03 04:41:44 +00:00
|
|
|
// 32-bit compares use the icc flags, 64-bit uses the xcc flags.
|
|
|
|
Opc = LHS.getValueType() == MVT::i32 ? SPISD::BRICC : SPISD::BRXCC;
|
2008-03-17 03:21:36 +00:00
|
|
|
} else {
|
2010-12-21 02:38:05 +00:00
|
|
|
CompareFlag = DAG.getNode(SPISD::CMPFCC, dl, MVT::Glue, LHS, RHS);
|
2008-03-17 03:21:36 +00:00
|
|
|
if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC);
|
|
|
|
Opc = SPISD::BRFCC;
|
|
|
|
}
|
2009-08-11 20:47:22 +00:00
|
|
|
return DAG.getNode(Opc, dl, MVT::Other, Chain, Dest,
|
|
|
|
DAG.getConstant(SPCC, MVT::i32), CompareFlag);
|
2008-03-17 03:21:36 +00:00
|
|
|
}
|
|
|
|
|
2008-07-27 21:46:04 +00:00
|
|
|
static SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) {
|
|
|
|
SDValue LHS = Op.getOperand(0);
|
|
|
|
SDValue RHS = Op.getOperand(1);
|
2008-03-17 03:21:36 +00:00
|
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue TrueVal = Op.getOperand(2);
|
|
|
|
SDValue FalseVal = Op.getOperand(3);
|
2009-02-05 22:07:54 +00:00
|
|
|
DebugLoc dl = Op.getDebugLoc();
|
2008-03-17 03:21:36 +00:00
|
|
|
unsigned Opc, SPCC = ~0U;
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 03:21:36 +00: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-10 20:27:31 +00:00
|
|
|
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue CompareFlag;
|
2013-04-04 03:08:00 +00:00
|
|
|
if (LHS.getValueType().isInteger()) {
|
2013-03-07 20:33:29 +00:00
|
|
|
// subcc returns a value
|
|
|
|
EVT VTs[] = { LHS.getValueType(), MVT::Glue };
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Ops[2] = { LHS, RHS };
|
2009-02-05 22:07:54 +00:00
|
|
|
CompareFlag = DAG.getNode(SPISD::CMPICC, dl, VTs, Ops, 2).getValue(1);
|
2013-04-04 03:08:00 +00:00
|
|
|
Opc = LHS.getValueType() == MVT::i32 ?
|
|
|
|
SPISD::SELECT_ICC : SPISD::SELECT_XCC;
|
2008-03-17 03:21:36 +00:00
|
|
|
if (SPCC == ~0U) SPCC = IntCondCCodeToICC(CC);
|
|
|
|
} else {
|
2010-12-21 02:38:05 +00:00
|
|
|
CompareFlag = DAG.getNode(SPISD::CMPFCC, dl, MVT::Glue, LHS, RHS);
|
2008-03-17 03:21:36 +00:00
|
|
|
Opc = SPISD::SELECT_FCC;
|
|
|
|
if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC);
|
|
|
|
}
|
2009-02-05 22:07:54 +00:00
|
|
|
return DAG.getNode(Opc, dl, TrueVal.getValueType(), TrueVal, FalseVal,
|
2009-08-11 20:47:22 +00:00
|
|
|
DAG.getConstant(SPCC, MVT::i32), CompareFlag);
|
2008-03-17 03:21:36 +00:00
|
|
|
}
|
|
|
|
|
2008-07-27 21:46:04 +00:00
|
|
|
static SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG,
|
2010-04-17 15:26:15 +00:00
|
|
|
const SparcTargetLowering &TLI) {
|
2010-04-17 14:41:14 +00:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
|
|
|
|
|
2008-03-17 03:21:36 +00:00
|
|
|
// vastart just stores the address of the VarArgsFrameIndex slot into the
|
|
|
|
// memory location argument.
|
2013-04-20 22:49:16 +00:00
|
|
|
DebugLoc DL = Op.getDebugLoc();
|
2010-04-17 14:41:14 +00:00
|
|
|
SDValue Offset =
|
2013-04-20 22:49:16 +00:00
|
|
|
DAG.getNode(ISD::ADD, DL, TLI.getPointerTy(),
|
|
|
|
DAG.getRegister(SP::I6, TLI.getPointerTy()),
|
|
|
|
DAG.getIntPtrConstant(FuncInfo->getVarArgsFrameOffset()));
|
2008-03-17 03:21:36 +00:00
|
|
|
const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
|
2013-04-20 22:49:16 +00:00
|
|
|
return DAG.getStore(Op.getOperand(0), DL, Offset, Op.getOperand(1),
|
2010-09-21 18:41:36 +00:00
|
|
|
MachinePointerInfo(SV), false, false, 0);
|
2008-03-17 03:21:36 +00:00
|
|
|
}
|
|
|
|
|
2008-07-27 21:46:04 +00:00
|
|
|
static SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) {
|
2008-08-28 21:40:38 +00:00
|
|
|
SDNode *Node = Op.getNode();
|
2009-08-10 22:56:29 +00:00
|
|
|
EVT VT = Node->getValueType(0);
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue InChain = Node->getOperand(0);
|
|
|
|
SDValue VAListPtr = Node->getOperand(1);
|
2013-04-20 22:49:16 +00:00
|
|
|
EVT PtrVT = VAListPtr.getValueType();
|
2008-03-17 03:21:36 +00:00
|
|
|
const Value *SV = cast<SrcValueSDNode>(Node->getOperand(2))->getValue();
|
2013-04-20 22:49:16 +00:00
|
|
|
DebugLoc DL = Node->getDebugLoc();
|
|
|
|
SDValue VAList = DAG.getLoad(PtrVT, DL, InChain, VAListPtr,
|
2011-11-08 18:42:53 +00:00
|
|
|
MachinePointerInfo(SV), false, false, false, 0);
|
2013-04-20 22:49:16 +00:00
|
|
|
// Increment the pointer, VAList, to the next vaarg.
|
|
|
|
SDValue NextPtr = DAG.getNode(ISD::ADD, DL, PtrVT, VAList,
|
|
|
|
DAG.getIntPtrConstant(VT.getSizeInBits()/8));
|
|
|
|
// Store the incremented VAList to the legalized pointer.
|
|
|
|
InChain = DAG.getStore(VAList.getValue(1), DL, NextPtr,
|
2010-09-21 18:41:36 +00:00
|
|
|
VAListPtr, MachinePointerInfo(SV), false, false, 0);
|
2013-04-20 22:49:16 +00:00
|
|
|
// Load the actual argument out of the pointer VAList.
|
|
|
|
// We can't count on greater alignment than the word size.
|
|
|
|
return DAG.getLoad(VT, DL, InChain, VAList, MachinePointerInfo(),
|
|
|
|
false, false, false,
|
|
|
|
std::min(PtrVT.getSizeInBits(), VT.getSizeInBits())/8);
|
2008-03-17 03:21:36 +00:00
|
|
|
}
|
|
|
|
|
2008-07-27 21:46:04 +00: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-04 23:02:30 +00:00
|
|
|
DebugLoc dl = Op.getDebugLoc();
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 03:21:36 +00:00
|
|
|
unsigned SPReg = SP::O6;
|
2009-08-11 20:47:22 +00:00
|
|
|
SDValue SP = DAG.getCopyFromReg(Chain, dl, SPReg, MVT::i32);
|
|
|
|
SDValue NewSP = DAG.getNode(ISD::SUB, dl, MVT::i32, SP, Size); // Value
|
2009-02-04 23:02:30 +00:00
|
|
|
Chain = DAG.getCopyToReg(SP.getValue(1), dl, SPReg, NewSP); // Output chain
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 03:21:36 +00:00
|
|
|
// The resultant pointer is actually 16 words from the bottom of the stack,
|
|
|
|
// to provide a register spill area.
|
2009-08-11 20:47:22 +00:00
|
|
|
SDValue NewVal = DAG.getNode(ISD::ADD, dl, MVT::i32, NewSP,
|
|
|
|
DAG.getConstant(96, MVT::i32));
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Ops[2] = { NewVal, Chain };
|
2009-02-04 23:02:30 +00:00
|
|
|
return DAG.getMergeValues(Ops, 2, dl);
|
2008-03-17 03:21:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-21 22:00:00 +00:00
|
|
|
static SDValue getFLUSHW(SDValue Op, SelectionDAG &DAG) {
|
2011-01-12 05:08:36 +00:00
|
|
|
DebugLoc dl = Op.getDebugLoc();
|
2011-01-21 22:00:00 +00:00
|
|
|
SDValue Chain = DAG.getNode(SPISD::FLUSHW,
|
2011-01-12 05:08:36 +00: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-21 22:00:00 +00:00
|
|
|
if (depth == 0)
|
2011-01-12 05:08:36 +00:00
|
|
|
FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, FrameReg, VT);
|
|
|
|
else {
|
|
|
|
// flush first to make sure the windowed registers' values are in stack
|
2011-01-21 22:00:00 +00:00
|
|
|
SDValue Chain = getFLUSHW(Op, DAG);
|
2011-01-12 05:08:36 +00:00
|
|
|
FrameAddr = DAG.getCopyFromReg(Chain, dl, FrameReg, VT);
|
2011-01-21 22:00:00 +00:00
|
|
|
|
2011-01-12 05:08:36 +00:00
|
|
|
for (uint64_t i = 0; i != depth; ++i) {
|
2011-01-21 22:00:00 +00:00
|
|
|
SDValue Ptr = DAG.getNode(ISD::ADD,
|
2011-01-12 05:08:36 +00:00
|
|
|
dl, MVT::i32,
|
|
|
|
FrameAddr, DAG.getIntPtrConstant(56));
|
2011-01-21 22:00:00 +00:00
|
|
|
FrameAddr = DAG.getLoad(MVT::i32, dl,
|
|
|
|
Chain,
|
2011-01-12 05:08:36 +00:00
|
|
|
Ptr,
|
2011-11-08 18:42:53 +00:00
|
|
|
MachinePointerInfo(), false, false, false, 0);
|
2011-01-12 05:08:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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-21 22:00:00 +00:00
|
|
|
if (depth == 0)
|
2011-01-12 05:08:36 +00:00
|
|
|
RetAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, RetReg, VT);
|
|
|
|
else {
|
|
|
|
// flush first to make sure the windowed registers' values are in stack
|
2011-01-21 22:00:00 +00:00
|
|
|
SDValue Chain = getFLUSHW(Op, DAG);
|
2011-01-12 05:08:36 +00:00
|
|
|
RetAddr = DAG.getCopyFromReg(Chain, dl, SP::I6, VT);
|
2011-01-21 22:00:00 +00:00
|
|
|
|
2011-01-12 05:08:36 +00:00
|
|
|
for (uint64_t i = 0; i != depth; ++i) {
|
2011-01-21 22:00:00 +00:00
|
|
|
SDValue Ptr = DAG.getNode(ISD::ADD,
|
2011-01-12 05:08:36 +00:00
|
|
|
dl, MVT::i32,
|
2011-01-21 22:00:00 +00:00
|
|
|
RetAddr,
|
2011-01-12 05:08:36 +00:00
|
|
|
DAG.getIntPtrConstant((i == depth-1)?60:56));
|
2011-01-21 22:00:00 +00:00
|
|
|
RetAddr = DAG.getLoad(MVT::i32, dl,
|
|
|
|
Chain,
|
2011-01-12 05:08:36 +00:00
|
|
|
Ptr,
|
2011-11-08 18:42:53 +00:00
|
|
|
MachinePointerInfo(), false, false, false, 0);
|
2011-01-12 05:08:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return RetAddr;
|
|
|
|
}
|
|
|
|
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue SparcTargetLowering::
|
2010-04-17 15:26:15 +00:00
|
|
|
LowerOperation(SDValue Op, SelectionDAG &DAG) const {
|
2008-03-17 03:21:36 +00:00
|
|
|
switch (Op.getOpcode()) {
|
2009-07-14 16:55:14 +00:00
|
|
|
default: llvm_unreachable("Should not custom lower this!");
|
2011-01-12 05:08:36 +00:00
|
|
|
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);
|
|
|
|
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
|
2008-03-17 03:21:36 +00:00
|
|
|
case ISD::GlobalTLSAddress:
|
2009-07-14 16:55:14 +00:00
|
|
|
llvm_unreachable("TLS not implemented for Sparc.");
|
2009-09-15 17:46:24 +00:00
|
|
|
case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG);
|
|
|
|
case ISD::ConstantPool: return LowerConstantPool(Op, DAG);
|
2008-03-17 03:21:36 +00: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 00:01:06 +00:00
|
|
|
MachineBasicBlock *BB) const {
|
2008-03-17 03:21:36 +00:00
|
|
|
const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo();
|
|
|
|
unsigned BROpcode;
|
|
|
|
unsigned CC;
|
2009-02-13 02:31:35 +00:00
|
|
|
DebugLoc dl = MI->getDebugLoc();
|
2008-03-17 03:21:36 +00:00
|
|
|
// Figure out the conditional branch opcode to use for this select_cc.
|
|
|
|
switch (MI->getOpcode()) {
|
2009-07-14 16:55:14 +00:00
|
|
|
default: llvm_unreachable("Unknown SELECT_CC!");
|
2008-03-17 03:21:36 +00: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-10 20:27:31 +00:00
|
|
|
|
2008-03-17 03:21:36 +00: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-07 23:14:23 +00:00
|
|
|
MachineFunction::iterator It = BB;
|
2008-03-17 03:21:36 +00:00
|
|
|
++It;
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 03:21:36 +00:00
|
|
|
// thisMBB:
|
|
|
|
// ...
|
|
|
|
// TrueVal = ...
|
|
|
|
// [f]bCC copy1MBB
|
|
|
|
// fallthrough --> copy0MBB
|
|
|
|
MachineBasicBlock *thisMBB = BB;
|
|
|
|
MachineFunction *F = BB->getParent();
|
2008-07-07 23:14:23 +00:00
|
|
|
MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB);
|
|
|
|
MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB);
|
2010-12-28 20:39:17 +00:00
|
|
|
F->insert(It, copy0MBB);
|
|
|
|
F->insert(It, sinkMBB);
|
2010-07-06 20:24:04 +00: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 02:31:35 +00:00
|
|
|
BuildMI(BB, dl, TII.get(BROpcode)).addMBB(sinkMBB).addImm(CC);
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 03:21:36 +00:00
|
|
|
// copy0MBB:
|
|
|
|
// %FalseValue = ...
|
|
|
|
// # fallthrough to sinkMBB
|
|
|
|
BB = copy0MBB;
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 03:21:36 +00:00
|
|
|
// Update machine-CFG edges
|
|
|
|
BB->addSuccessor(sinkMBB);
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2008-03-17 03:21:36 +00:00
|
|
|
// sinkMBB:
|
|
|
|
// %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ]
|
|
|
|
// ...
|
|
|
|
BB = sinkMBB;
|
2010-07-06 20:24:04 +00:00
|
|
|
BuildMI(*BB, BB->begin(), dl, TII.get(SP::PHI), MI->getOperand(0).getReg())
|
2008-03-17 03:21:36 +00:00
|
|
|
.addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB)
|
|
|
|
.addReg(MI->getOperand(1).getReg()).addMBB(thisMBB);
|
2008-10-10 20:27:31 +00:00
|
|
|
|
2010-07-06 20:24:04 +00:00
|
|
|
MI->eraseFromParent(); // The pseudo instruction is gone now.
|
2008-03-17 03:21:36 +00:00
|
|
|
return BB;
|
|
|
|
}
|
2008-10-10 20:28:10 +00: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-10 22:56:29 +00:00
|
|
|
EVT VT) const {
|
2008-10-10 20:28:10 +00:00
|
|
|
if (Constraint.size() == 1) {
|
|
|
|
switch (Constraint[0]) {
|
|
|
|
case 'r':
|
2012-04-20 06:31:50 +00:00
|
|
|
return std::make_pair(0U, &SP::IntRegsRegClass);
|
2008-10-10 20:28:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT);
|
|
|
|
}
|
|
|
|
|
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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@57748 91177308-0d34-0410-b5e6-96231b3b80d8
2008-10-18 02:06:02 +00:00
|
|
|
bool
|
|
|
|
SparcTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const {
|
|
|
|
// The Sparc target isn't yet aware of offsets.
|
|
|
|
return false;
|
|
|
|
}
|