mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-03 13:31:05 +00:00
Add X86FastISel support for return statements. This entails refactoring
a bunch of stuff, to allow the target-independent calling convention logic to be employed. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@107800 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
ced9ec9bac
commit
f423a69839
@ -188,8 +188,7 @@ public:
|
||||
/// CheckReturn - Analyze the return values of a function, returning
|
||||
/// true if the return can be performed without sret-demotion, and
|
||||
/// false otherwise.
|
||||
bool CheckReturn(const SmallVectorImpl<EVT> &OutTys,
|
||||
const SmallVectorImpl<ISD::ArgFlagsTy> &ArgsFlags,
|
||||
bool CheckReturn(const SmallVectorImpl<ISD::OutputArg> &ArgsFlags,
|
||||
CCAssignFn Fn);
|
||||
|
||||
/// AnalyzeCallOperands - Analyze the outgoing arguments to a call,
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "llvm/CallingConv.h"
|
||||
#include "llvm/InlineAsm.h"
|
||||
#include "llvm/Attributes.h"
|
||||
#include "llvm/CodeGen/SelectionDAGNodes.h"
|
||||
#include "llvm/CodeGen/RuntimeLibcalls.h"
|
||||
#include "llvm/ADT/APFloat.h"
|
||||
@ -1159,8 +1160,7 @@ public:
|
||||
/// registers. If false is returned, an sret-demotion is performed.
|
||||
///
|
||||
virtual bool CanLowerReturn(CallingConv::ID CallConv, bool isVarArg,
|
||||
const SmallVectorImpl<EVT> &OutTys,
|
||||
const SmallVectorImpl<ISD::ArgFlagsTy> &ArgsFlags,
|
||||
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
||||
LLVMContext &Context) const
|
||||
{
|
||||
// Return true by default to get preexisting behavior.
|
||||
@ -1656,6 +1656,15 @@ protected:
|
||||
/// optimization.
|
||||
bool benefitFromCodePlacementOpt;
|
||||
};
|
||||
|
||||
/// GetReturnInfo - Given an LLVM IR type and return type attributes,
|
||||
/// compute the return value EVTs and flags, and optionally also
|
||||
/// the offsets, if the return value is being lowered to memory.
|
||||
void GetReturnInfo(const Type* ReturnType, Attributes attr,
|
||||
SmallVectorImpl<ISD::OutputArg> &Outs,
|
||||
const TargetLowering &TLI,
|
||||
SmallVectorImpl<uint64_t> *Offsets = 0);
|
||||
|
||||
} // end llvm namespace
|
||||
|
||||
#endif
|
||||
|
@ -80,13 +80,12 @@ CCState::AnalyzeFormalArguments(const SmallVectorImpl<ISD::InputArg> &Ins,
|
||||
|
||||
/// CheckReturn - Analyze the return values of a function, returning true if
|
||||
/// the return can be performed without sret-demotion, and false otherwise.
|
||||
bool CCState::CheckReturn(const SmallVectorImpl<EVT> &OutTys,
|
||||
const SmallVectorImpl<ISD::ArgFlagsTy> &ArgsFlags,
|
||||
bool CCState::CheckReturn(const SmallVectorImpl<ISD::OutputArg> &Outs,
|
||||
CCAssignFn Fn) {
|
||||
// Determine which register each value should be copied into.
|
||||
for (unsigned i = 0, e = OutTys.size(); i != e; ++i) {
|
||||
EVT VT = OutTys[i];
|
||||
ISD::ArgFlagsTy ArgFlags = ArgsFlags[i];
|
||||
for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
|
||||
EVT VT = Outs[i].VT;
|
||||
ISD::ArgFlagsTy ArgFlags = Outs[i].Flags;
|
||||
if (Fn(i, VT, VT, CCValAssign::Full, ArgFlags, *this))
|
||||
return false;
|
||||
}
|
||||
|
@ -963,67 +963,6 @@ SDValue SelectionDAGBuilder::getValueImpl(const Value *V) {
|
||||
return SDValue();
|
||||
}
|
||||
|
||||
/// Get the EVTs and ArgFlags collections that represent the legalized return
|
||||
/// type of the given function. This does not require a DAG or a return value,
|
||||
/// and is suitable for use before any DAGs for the function are constructed.
|
||||
static void getReturnInfo(const Type* ReturnType,
|
||||
Attributes attr, SmallVectorImpl<EVT> &OutVTs,
|
||||
SmallVectorImpl<ISD::ArgFlagsTy> &OutFlags,
|
||||
const TargetLowering &TLI,
|
||||
SmallVectorImpl<uint64_t> *Offsets = 0) {
|
||||
SmallVector<EVT, 4> ValueVTs;
|
||||
ComputeValueVTs(TLI, ReturnType, ValueVTs);
|
||||
unsigned NumValues = ValueVTs.size();
|
||||
if (NumValues == 0) return;
|
||||
unsigned Offset = 0;
|
||||
|
||||
for (unsigned j = 0, f = NumValues; j != f; ++j) {
|
||||
EVT VT = ValueVTs[j];
|
||||
ISD::NodeType ExtendKind = ISD::ANY_EXTEND;
|
||||
|
||||
if (attr & Attribute::SExt)
|
||||
ExtendKind = ISD::SIGN_EXTEND;
|
||||
else if (attr & Attribute::ZExt)
|
||||
ExtendKind = ISD::ZERO_EXTEND;
|
||||
|
||||
// FIXME: C calling convention requires the return type to be promoted to
|
||||
// at least 32-bit. But this is not necessary for non-C calling
|
||||
// conventions. The frontend should mark functions whose return values
|
||||
// require promoting with signext or zeroext attributes.
|
||||
if (ExtendKind != ISD::ANY_EXTEND && VT.isInteger()) {
|
||||
EVT MinVT = TLI.getRegisterType(ReturnType->getContext(), MVT::i32);
|
||||
if (VT.bitsLT(MinVT))
|
||||
VT = MinVT;
|
||||
}
|
||||
|
||||
unsigned NumParts = TLI.getNumRegisters(ReturnType->getContext(), VT);
|
||||
EVT PartVT = TLI.getRegisterType(ReturnType->getContext(), VT);
|
||||
unsigned PartSize = TLI.getTargetData()->getTypeAllocSize(
|
||||
PartVT.getTypeForEVT(ReturnType->getContext()));
|
||||
|
||||
// 'inreg' on function refers to return value
|
||||
ISD::ArgFlagsTy Flags = ISD::ArgFlagsTy();
|
||||
if (attr & Attribute::InReg)
|
||||
Flags.setInReg();
|
||||
|
||||
// Propagate extension type if any
|
||||
if (attr & Attribute::SExt)
|
||||
Flags.setSExt();
|
||||
else if (attr & Attribute::ZExt)
|
||||
Flags.setZExt();
|
||||
|
||||
for (unsigned i = 0; i < NumParts; ++i) {
|
||||
OutVTs.push_back(PartVT);
|
||||
OutFlags.push_back(Flags);
|
||||
if (Offsets)
|
||||
{
|
||||
Offsets->push_back(Offset);
|
||||
Offset += PartSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SelectionDAGBuilder::visitRet(const ReturnInst &I) {
|
||||
SDValue Chain = getControlRoot();
|
||||
SmallVector<ISD::OutputArg, 8> Outs;
|
||||
@ -4559,14 +4498,13 @@ void SelectionDAGBuilder::LowerCallTo(ImmutableCallSite CS, SDValue Callee,
|
||||
Args.reserve(CS.arg_size());
|
||||
|
||||
// Check whether the function can return without sret-demotion.
|
||||
SmallVector<EVT, 4> OutVTs;
|
||||
SmallVector<ISD::ArgFlagsTy, 4> OutsFlags;
|
||||
SmallVector<ISD::OutputArg, 4> Outs;
|
||||
SmallVector<uint64_t, 4> Offsets;
|
||||
getReturnInfo(RetTy, CS.getAttributes().getRetAttributes(),
|
||||
OutVTs, OutsFlags, TLI, &Offsets);
|
||||
GetReturnInfo(RetTy, CS.getAttributes().getRetAttributes(),
|
||||
Outs, TLI, &Offsets);
|
||||
|
||||
bool CanLowerReturn = TLI.CanLowerReturn(CS.getCallingConv(),
|
||||
FTy->isVarArg(), OutVTs, OutsFlags, FTy->getContext());
|
||||
FTy->isVarArg(), Outs, FTy->getContext());
|
||||
|
||||
SDValue DemoteStackSlot;
|
||||
|
||||
@ -4659,7 +4597,7 @@ void SelectionDAGBuilder::LowerCallTo(ImmutableCallSite CS, SDValue Callee,
|
||||
ComputeValueVTs(TLI, PtrRetTy, PVTs);
|
||||
assert(PVTs.size() == 1 && "Pointers should fit in one register");
|
||||
EVT PtrVT = PVTs[0];
|
||||
unsigned NumValues = OutVTs.size();
|
||||
unsigned NumValues = Outs.size();
|
||||
SmallVector<SDValue, 4> Values(NumValues);
|
||||
SmallVector<SDValue, 4> Chains(NumValues);
|
||||
|
||||
@ -4667,7 +4605,7 @@ void SelectionDAGBuilder::LowerCallTo(ImmutableCallSite CS, SDValue Callee,
|
||||
SDValue Add = DAG.getNode(ISD::ADD, getCurDebugLoc(), PtrVT,
|
||||
DemoteStackSlot,
|
||||
DAG.getConstant(Offsets[i], PtrVT));
|
||||
SDValue L = DAG.getLoad(OutVTs[i], getCurDebugLoc(), Result.second,
|
||||
SDValue L = DAG.getLoad(Outs[i].VT, getCurDebugLoc(), Result.second,
|
||||
Add, NULL, Offsets[i], false, false, 1);
|
||||
Values[i] = L;
|
||||
Chains[i] = L.getValue(1);
|
||||
@ -5959,15 +5897,13 @@ void SelectionDAGISel::LowerArguments(const BasicBlock *LLVMBB) {
|
||||
SmallVector<ISD::InputArg, 16> Ins;
|
||||
|
||||
// Check whether the function can return without sret-demotion.
|
||||
SmallVector<EVT, 4> OutVTs;
|
||||
SmallVector<ISD::ArgFlagsTy, 4> OutsFlags;
|
||||
getReturnInfo(F.getReturnType(), F.getAttributes().getRetAttributes(),
|
||||
OutVTs, OutsFlags, TLI);
|
||||
SmallVector<ISD::OutputArg, 4> Outs;
|
||||
GetReturnInfo(F.getReturnType(), F.getAttributes().getRetAttributes(),
|
||||
Outs, TLI);
|
||||
|
||||
FuncInfo->CanLowerReturn = TLI.CanLowerReturn(F.getCallingConv(),
|
||||
F.isVarArg(),
|
||||
OutVTs, OutsFlags,
|
||||
F.getContext());
|
||||
Outs, F.getContext());
|
||||
if (!FuncInfo->CanLowerReturn) {
|
||||
// Put in an sret pointer parameter before all the other parameters.
|
||||
SmallVector<EVT, 1> ValueVTs;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
#include "llvm/GlobalVariable.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/CodeGen/Analysis.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineJumpTableInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
@ -838,6 +839,65 @@ unsigned TargetLowering::getVectorTypeBreakdown(LLVMContext &Context, EVT VT,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// Get the EVTs and ArgFlags collections that represent the legalized return
|
||||
/// type of the given function. This does not require a DAG or a return value,
|
||||
/// and is suitable for use before any DAGs for the function are constructed.
|
||||
/// TODO: Move this out of TargetLowering.cpp.
|
||||
void llvm::GetReturnInfo(const Type* ReturnType, Attributes attr,
|
||||
SmallVectorImpl<ISD::OutputArg> &Outs,
|
||||
const TargetLowering &TLI,
|
||||
SmallVectorImpl<uint64_t> *Offsets) {
|
||||
SmallVector<EVT, 4> ValueVTs;
|
||||
ComputeValueVTs(TLI, ReturnType, ValueVTs);
|
||||
unsigned NumValues = ValueVTs.size();
|
||||
if (NumValues == 0) return;
|
||||
unsigned Offset = 0;
|
||||
|
||||
for (unsigned j = 0, f = NumValues; j != f; ++j) {
|
||||
EVT VT = ValueVTs[j];
|
||||
ISD::NodeType ExtendKind = ISD::ANY_EXTEND;
|
||||
|
||||
if (attr & Attribute::SExt)
|
||||
ExtendKind = ISD::SIGN_EXTEND;
|
||||
else if (attr & Attribute::ZExt)
|
||||
ExtendKind = ISD::ZERO_EXTEND;
|
||||
|
||||
// FIXME: C calling convention requires the return type to be promoted to
|
||||
// at least 32-bit. But this is not necessary for non-C calling
|
||||
// conventions. The frontend should mark functions whose return values
|
||||
// require promoting with signext or zeroext attributes.
|
||||
if (ExtendKind != ISD::ANY_EXTEND && VT.isInteger()) {
|
||||
EVT MinVT = TLI.getRegisterType(ReturnType->getContext(), MVT::i32);
|
||||
if (VT.bitsLT(MinVT))
|
||||
VT = MinVT;
|
||||
}
|
||||
|
||||
unsigned NumParts = TLI.getNumRegisters(ReturnType->getContext(), VT);
|
||||
EVT PartVT = TLI.getRegisterType(ReturnType->getContext(), VT);
|
||||
unsigned PartSize = TLI.getTargetData()->getTypeAllocSize(
|
||||
PartVT.getTypeForEVT(ReturnType->getContext()));
|
||||
|
||||
// 'inreg' on function refers to return value
|
||||
ISD::ArgFlagsTy Flags = ISD::ArgFlagsTy();
|
||||
if (attr & Attribute::InReg)
|
||||
Flags.setInReg();
|
||||
|
||||
// Propagate extension type if any
|
||||
if (attr & Attribute::SExt)
|
||||
Flags.setSExt();
|
||||
else if (attr & Attribute::ZExt)
|
||||
Flags.setZExt();
|
||||
|
||||
for (unsigned i = 0; i < NumParts; ++i) {
|
||||
Outs.push_back(ISD::OutputArg(Flags, PartVT, /*isFixed=*/true));
|
||||
if (Offsets) {
|
||||
Offsets->push_back(Offset);
|
||||
Offset += PartSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// getByValTypeAlignment - Return the desired alignment for ByVal aggregate
|
||||
/// function arguments in the caller parameter area. This is the actual
|
||||
/// alignment, not its logarithm.
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "llvm/GlobalVariable.h"
|
||||
#include "llvm/Instructions.h"
|
||||
#include "llvm/IntrinsicInst.h"
|
||||
#include "llvm/CodeGen/Analysis.h"
|
||||
#include "llvm/CodeGen/FastISel.h"
|
||||
#include "llvm/CodeGen/FunctionLoweringInfo.h"
|
||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
||||
@ -84,6 +85,8 @@ private:
|
||||
|
||||
bool X86SelectStore(const Instruction *I);
|
||||
|
||||
bool X86SelectRet(const Instruction *I);
|
||||
|
||||
bool X86SelectCmp(const Instruction *I);
|
||||
|
||||
bool X86SelectZExt(const Instruction *I);
|
||||
@ -660,6 +663,67 @@ bool X86FastISel::X86SelectStore(const Instruction *I) {
|
||||
return X86FastEmitStore(VT, I->getOperand(0), AM);
|
||||
}
|
||||
|
||||
/// X86SelectRet - Select and emit code to implement ret instructions.
|
||||
bool X86FastISel::X86SelectRet(const Instruction *I) {
|
||||
const ReturnInst *Ret = cast<ReturnInst>(I);
|
||||
const Function &F = *I->getParent()->getParent();
|
||||
|
||||
if (!FuncInfo.CanLowerReturn)
|
||||
return false;
|
||||
|
||||
CallingConv::ID CC = F.getCallingConv();
|
||||
if (CC != CallingConv::C &&
|
||||
CC != CallingConv::Fast &&
|
||||
CC != CallingConv::X86_FastCall)
|
||||
return false;
|
||||
|
||||
if (Subtarget->isTargetWin64())
|
||||
return false;
|
||||
|
||||
// fastcc with -tailcallopt is intended to provide a guaranteed
|
||||
// tail call optimization. Fastisel doesn't know how to do that.
|
||||
if (CC == CallingConv::Fast && GuaranteedTailCallOpt)
|
||||
return false;
|
||||
|
||||
// Let SDISel handle vararg functions.
|
||||
if (F.isVarArg())
|
||||
return false;
|
||||
|
||||
SmallVector<ISD::OutputArg, 4> Outs;
|
||||
GetReturnInfo(F.getReturnType(), F.getAttributes().getRetAttributes(),
|
||||
Outs, TLI);
|
||||
|
||||
// Analyze operands of the call, assigning locations to each operand.
|
||||
SmallVector<CCValAssign, 16> ValLocs;
|
||||
CCState CCInfo(CC, F.isVarArg(), TM, ValLocs, I->getContext());
|
||||
CCInfo.AnalyzeReturn(Outs, CCAssignFnForCall(CC));
|
||||
|
||||
// Copy the return value into registers.
|
||||
for (unsigned i = 0, e = ValLocs.size(); i != e; ++i) {
|
||||
CCValAssign &VA = ValLocs[i];
|
||||
|
||||
// Don't bother handling odd stuff for now.
|
||||
if (VA.getLocInfo() != CCValAssign::Full)
|
||||
return false;
|
||||
if (!VA.isRegLoc())
|
||||
return false;
|
||||
|
||||
const Value *RV = Ret->getOperand(VA.getValNo());
|
||||
unsigned Reg = getRegForValue(RV);
|
||||
|
||||
TargetRegisterClass* RC = TLI.getRegClassFor(VA.getValVT());
|
||||
bool Emitted = TII.copyRegToReg(*FuncInfo.MBB, FuncInfo.InsertPt,
|
||||
VA.getLocReg(), Reg, RC, RC, DL);
|
||||
assert(Emitted && "Failed to emit a copy instruction!"); Emitted=Emitted;
|
||||
|
||||
MRI.addLiveOut(X86::XMM0);
|
||||
}
|
||||
|
||||
// Now emit the RET.
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(X86::RET));
|
||||
return true;
|
||||
}
|
||||
|
||||
/// X86SelectLoad - Select and emit code to implement load instructions.
|
||||
///
|
||||
bool X86FastISel::X86SelectLoad(const Instruction *I) {
|
||||
@ -1194,14 +1258,18 @@ bool X86FastISel::X86SelectExtractValue(const Instruction *I) {
|
||||
switch (CI->getIntrinsicID()) {
|
||||
default: break;
|
||||
case Intrinsic::sadd_with_overflow:
|
||||
case Intrinsic::uadd_with_overflow:
|
||||
case Intrinsic::uadd_with_overflow: {
|
||||
// Cheat a little. We know that the registers for "add" and "seto" are
|
||||
// allocated sequentially. However, we only keep track of the register
|
||||
// for "add" in the value map. Use extractvalue's index to get the
|
||||
// correct register for "seto".
|
||||
UpdateValueMap(I, lookUpRegForValue(Agg) + *EI->idx_begin());
|
||||
unsigned OpReg = getRegForValue(Agg);
|
||||
if (OpReg == 0)
|
||||
return false;
|
||||
UpdateValueMap(I, OpReg + *EI->idx_begin());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -1664,6 +1732,8 @@ X86FastISel::TargetSelectInstruction(const Instruction *I) {
|
||||
return X86SelectLoad(I);
|
||||
case Instruction::Store:
|
||||
return X86SelectStore(I);
|
||||
case Instruction::Ret:
|
||||
return X86SelectRet(I);
|
||||
case Instruction::ICmp:
|
||||
case Instruction::FCmp:
|
||||
return X86SelectCmp(I);
|
||||
|
@ -1218,13 +1218,12 @@ bool X86TargetLowering::getStackCookieLocation(unsigned &AddressSpace,
|
||||
|
||||
bool
|
||||
X86TargetLowering::CanLowerReturn(CallingConv::ID CallConv, bool isVarArg,
|
||||
const SmallVectorImpl<EVT> &OutTys,
|
||||
const SmallVectorImpl<ISD::ArgFlagsTy> &ArgsFlags,
|
||||
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
||||
LLVMContext &Context) const {
|
||||
SmallVector<CCValAssign, 16> RVLocs;
|
||||
CCState CCInfo(CallConv, isVarArg, getTargetMachine(),
|
||||
RVLocs, Context);
|
||||
return CCInfo.CheckReturn(OutTys, ArgsFlags, RetCC_X86);
|
||||
return CCInfo.CheckReturn(Outs, RetCC_X86);
|
||||
}
|
||||
|
||||
SDValue
|
||||
|
@ -740,8 +740,7 @@ namespace llvm {
|
||||
|
||||
virtual bool
|
||||
CanLowerReturn(CallingConv::ID CallConv, bool isVarArg,
|
||||
const SmallVectorImpl<EVT> &OutTys,
|
||||
const SmallVectorImpl<ISD::ArgFlagsTy> &ArgsFlags,
|
||||
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
||||
LLVMContext &Context) const;
|
||||
|
||||
void ReplaceATOMIC_BINARY_64(SDNode *N, SmallVectorImpl<SDValue> &Results,
|
||||
|
@ -1135,13 +1135,12 @@ XCoreTargetLowering::LowerCCCArguments(SDValue Chain,
|
||||
|
||||
bool XCoreTargetLowering::
|
||||
CanLowerReturn(CallingConv::ID CallConv, bool isVarArg,
|
||||
const SmallVectorImpl<EVT> &OutTys,
|
||||
const SmallVectorImpl<ISD::ArgFlagsTy> &ArgsFlags,
|
||||
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
||||
LLVMContext &Context) const {
|
||||
SmallVector<CCValAssign, 16> RVLocs;
|
||||
CCState CCInfo(CallConv, isVarArg, getTargetMachine(),
|
||||
RVLocs, Context);
|
||||
return CCInfo.CheckReturn(OutTys, ArgsFlags, RetCC_XCore);
|
||||
return CCInfo.CheckReturn(Outs, RetCC_XCore);
|
||||
}
|
||||
|
||||
SDValue
|
||||
|
@ -193,8 +193,7 @@ namespace llvm {
|
||||
|
||||
virtual bool
|
||||
CanLowerReturn(CallingConv::ID CallConv, bool isVarArg,
|
||||
const SmallVectorImpl<EVT> &OutTys,
|
||||
const SmallVectorImpl<ISD::ArgFlagsTy> &ArgsFlags,
|
||||
const SmallVectorImpl<ISD::OutputArg> &ArgsFlags,
|
||||
LLVMContext &Context) const;
|
||||
};
|
||||
}
|
||||
|
@ -14,8 +14,7 @@ define i32 @test1(i32 %t3, i32* %t1) nounwind {
|
||||
|
||||
; X64: test1:
|
||||
; X64: movslq %edi, %rax
|
||||
; X64: movl (%rsi,%rax,4), %eax
|
||||
; X64: ret
|
||||
; X64: movl (%rsi,%rax,4), %e
|
||||
|
||||
}
|
||||
define i32 @test2(i64 %t3, i32* %t1) nounwind {
|
||||
|
Loading…
Reference in New Issue
Block a user