[Hexagon] Overhaul of stack object allocation

- Use static allocation for aligned stack objects.
- Simplify dynamic stack object allocation.
- Simplify elimination of frame-indices.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235521 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Krzysztof Parzyszek 2015-04-22 16:43:53 +00:00
parent 1436ff81cc
commit 5ce227e787
10 changed files with 1318 additions and 437 deletions

File diff suppressed because it is too large Load Diff

View File

@ -15,17 +15,22 @@
namespace llvm {
class HexagonInstrInfo;
class HexagonFrameLowering : public TargetFrameLowering {
private:
void determineFrameLayout(MachineFunction &MF) const;
void expandAlloca(MachineInstr *AI, const HexagonInstrInfo &TII,
unsigned SP, unsigned CF) const;
public:
explicit HexagonFrameLowering() : TargetFrameLowering(StackGrowsDown, 8, 0) {}
explicit HexagonFrameLowering()
: TargetFrameLowering(StackGrowsDown, 8, 0, 1, true) {}
/// emitProlog/emitEpilog - These methods insert prolog and epilog code into
/// the function.
void emitPrologue(MachineFunction &MF) const override;
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
bool targetHandlesStackFrameRounding() const override {
return true;
}
bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const std::vector<CalleeSavedInfo> &CSI,
@ -41,9 +46,37 @@ public:
MachineBasicBlock::iterator MI,
const std::vector<CalleeSavedInfo> &CSI,
const TargetRegisterInfo *TRI) const override;
void processFunctionBeforeFrameFinalized(MachineFunction &MF,
RegScavenger *RS = NULL) const override;
void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
RegScavenger *RS) const override;
int getFrameIndexOffset(const MachineFunction &MF, int FI) const override;
bool hasFP(const MachineFunction &MF) const override;
bool hasTailCall(MachineBasicBlock &MBB) const;
void adjustForCalleeSavedRegsSpillCall(MachineFunction &MF) const;
bool replacePredRegPseudoSpillCode(MachineFunction &MF) const;
const SpillSlot *getCalleeSavedSpillSlots(unsigned &NumEntries)
const override {
static const SpillSlot Offsets[] = {
{ Hexagon::R17, -4 }, { Hexagon::R16, -8 }, { Hexagon::D8, -8 },
{ Hexagon::R19, -12 }, { Hexagon::R18, -16 }, { Hexagon::D9, -16 },
{ Hexagon::R21, -20 }, { Hexagon::R20, -24 }, { Hexagon::D10, -24 },
{ Hexagon::R23, -28 }, { Hexagon::R22, -32 }, { Hexagon::D11, -32 },
{ Hexagon::R25, -36 }, { Hexagon::R24, -40 }, { Hexagon::D12, -40 },
{ Hexagon::R27, -44 }, { Hexagon::R26, -48 }, { Hexagon::D13, -48 }
};
NumEntries = array_lengthof(Offsets);
return Offsets;
}
bool assignCalleeSavedSpillSlots(MachineFunction &MF,
const TargetRegisterInfo *TRI,
std::vector<CalleeSavedInfo> &CSI) const override;
bool needsAligna(const MachineFunction &MF) const;
MachineInstr *getAlignaInstr(MachineFunction &MF) const;
};
} // End llvm namespace

View File

@ -13,8 +13,11 @@
#include "Hexagon.h"
#include "HexagonISelLowering.h"
#include "HexagonMachineFunctionInfo.h"
#include "HexagonTargetMachine.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/CodeGen/FunctionLoweringInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/Support/CommandLine.h"
@ -62,6 +65,7 @@ public:
}
virtual void PreprocessISelDAG() override;
virtual void EmitFunctionEntryCode() override;
SDNode *Select(SDNode *N) override;
@ -1216,12 +1220,30 @@ SDNode *HexagonDAGToDAGISel::SelectBitOp(SDNode *N) {
SDNode *HexagonDAGToDAGISel::SelectFrameIndex(SDNode *N) {
MachineFrameInfo *MFI = MF->getFrameInfo();
const HexagonFrameLowering *HFI = HST->getFrameLowering();
int FX = cast<FrameIndexSDNode>(N)->getIndex();
unsigned StkA = HFI->getStackAlignment();
unsigned MaxA = MFI->getMaxAlignment();
SDValue FI = CurDAG->getTargetFrameIndex(FX, MVT::i32);
SDValue Zero = CurDAG->getTargetConstant(0, MVT::i32);
SDLoc DL(N);
SDNode *R = 0;
SDNode *R = CurDAG->getMachineNode(Hexagon::TFR_FI, DL, MVT::i32, FI, Zero);
// Use TFR_FI when:
// - the object is fixed, or
// - there are no objects with higher-than-default alignment, or
// - there are no dynamically allocated objects.
// Otherwise, use TFR_FIA.
if (FX < 0 || MaxA <= StkA || !MFI->hasVarSizedObjects()) {
R = CurDAG->getMachineNode(Hexagon::TFR_FI, DL, MVT::i32, FI, Zero);
} else {
auto &HMFI = *MF->getInfo<HexagonMachineFunctionInfo>();
unsigned AR = HMFI.getStackAlignBaseVReg();
SDValue CH = CurDAG->getEntryNode();
SDValue Ops[] = { CurDAG->getCopyFromReg(CH, DL, AR, MVT::i32), FI, Zero };
R = CurDAG->getMachineNode(Hexagon::TFR_FIA, DL, MVT::i32, Ops);
}
if (N->getHasDebugValue())
CurDAG->TransferDbgValues(SDValue(N, 0), SDValue(R, 0));
@ -1280,7 +1302,6 @@ SDNode *HexagonDAGToDAGISel::Select(SDNode *N) {
return SelectCode(N);
}
bool HexagonDAGToDAGISel::
SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
std::vector<SDValue> &OutOps) {
@ -1352,12 +1373,32 @@ void HexagonDAGToDAGISel::PreprocessISelDAG() {
}
}
void HexagonDAGToDAGISel::EmitFunctionEntryCode() {
auto &HST = static_cast<const HexagonSubtarget&>(MF->getSubtarget());
auto &HFI = *HST.getFrameLowering();
if (!HFI.needsAligna(*MF))
return;
MachineFrameInfo *MFI = MF->getFrameInfo();
MachineBasicBlock *EntryBB = MF->begin();
unsigned AR = FuncInfo->CreateReg(MVT::i32);
unsigned MaxA = MFI->getMaxAlignment();
auto &HII = *HST.getInstrInfo();
BuildMI(EntryBB, DebugLoc(), HII.get(Hexagon::ALIGNA), AR)
.addImm(MaxA);
MF->getInfo<HexagonMachineFunctionInfo>()->setStackAlignBaseVReg(AR);
}
// Match a frame index that can be used in an addressing mode.
bool HexagonDAGToDAGISel::SelectAddrFI(SDValue& N, SDValue &R) {
if (N.getOpcode() != ISD::FrameIndex)
return false;
FrameIndexSDNode *FX = cast<FrameIndexSDNode>(N);
R = CurDAG->getTargetFrameIndex(FX->getIndex(), MVT::i32);
auto &HFI = *HST->getFrameLowering();
MachineFrameInfo *MFI = MF->getFrameInfo();
int FX = cast<FrameIndexSDNode>(N)->getIndex();
if (!MFI->isFixedObjectIndex(FX) && HFI.needsAligna(*MF))
return false;
R = CurDAG->getTargetFrameIndex(FX, MVT::i32);
return true;
}

View File

@ -420,6 +420,7 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
bool doesNotReturn = CLI.DoesNotReturn;
bool IsStructRet = (Outs.empty()) ? false : Outs[0].Flags.isSRet();
MachineFunction &MF = DAG.getMachineFunction();
// Check for varargs.
int NumNamedVarArgParams = -1;
@ -444,41 +445,40 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
HexagonCCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs,
*DAG.getContext(), NumNamedVarArgParams);
if (NumNamedVarArgParams > 0)
if (isVarArg)
CCInfo.AnalyzeCallOperands(Outs, CC_Hexagon_VarArg);
else
CCInfo.AnalyzeCallOperands(Outs, CC_Hexagon);
if (DAG.getTarget().Options.DisableTailCalls)
isTailCall = false;
if(isTailCall) {
bool StructAttrFlag =
DAG.getMachineFunction().getFunction()->hasStructRetAttr();
if (isTailCall) {
bool StructAttrFlag = MF.getFunction()->hasStructRetAttr();
isTailCall = IsEligibleForTailCallOptimization(Callee, CallConv,
isVarArg, IsStructRet,
StructAttrFlag,
Outs, OutVals, Ins, DAG);
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i){
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
CCValAssign &VA = ArgLocs[i];
if (VA.isMemLoc()) {
isTailCall = false;
break;
}
}
if (isTailCall) {
DEBUG(dbgs () << "Eligible for Tail Call\n");
} else {
DEBUG(dbgs () <<
"Argument must be passed on stack. Not eligible for Tail Call\n");
}
DEBUG(dbgs() << (isTailCall ? "Eligible for Tail Call\n"
: "Argument must be passed on stack. "
"Not eligible for Tail Call\n"));
}
// Get a count of how many bytes are to be pushed on the stack.
unsigned NumBytes = CCInfo.getNextStackOffset();
SmallVector<std::pair<unsigned, SDValue>, 16> RegsToPass;
SmallVector<SDValue, 8> MemOpChains;
const HexagonRegisterInfo *QRI = Subtarget->getRegisterInfo();
SDValue StackPtr =
DAG.getCopyFromReg(Chain, dl, QRI->getStackRegister(), getPointerTy());
auto &HRI =
static_cast<const HexagonRegisterInfo&>(*Subtarget->getRegisterInfo());
SDValue StackPtr = DAG.getCopyFromReg(Chain, dl, HRI.getStackRegister(),
getPointerTy());
// Walk the register/memloc assignments, inserting copies/loads.
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
@ -491,6 +491,7 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
default:
// Loc info must be one of Full, SExt, ZExt, or AExt.
llvm_unreachable("Unknown loc info!");
case CCValAssign::BCvt:
case CCValAssign::Full:
break;
case CCValAssign::SExt:
@ -506,41 +507,37 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
if (VA.isMemLoc()) {
unsigned LocMemOffset = VA.getLocMemOffset();
SDValue PtrOff = DAG.getConstant(LocMemOffset, StackPtr.getValueType());
PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff);
SDValue MemAddr = DAG.getConstant(LocMemOffset, StackPtr.getValueType());
MemAddr = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, MemAddr);
if (Flags.isByVal()) {
// The argument is a struct passed by value. According to LLVM, "Arg"
// is is pointer.
MemOpChains.push_back(CreateCopyOfByValArgument(Arg, PtrOff, Chain,
MemOpChains.push_back(CreateCopyOfByValArgument(Arg, MemAddr, Chain,
Flags, DAG, dl));
} else {
// The argument is not passed by value. "Arg" is a buildin type. It is
// not a pointer.
MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff,
MachinePointerInfo(),false, false,
0));
MachinePointerInfo LocPI = MachinePointerInfo::getStack(LocMemOffset);
SDValue S = DAG.getStore(Chain, dl, Arg, MemAddr, LocPI, false,
false, 0);
MemOpChains.push_back(S);
}
continue;
}
// Arguments that can be passed on register must be kept at RegsToPass
// vector.
if (VA.isRegLoc()) {
if (VA.isRegLoc())
RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
}
}
// Transform all store nodes into one single node because all store
// nodes are independent of each other.
if (!MemOpChains.empty()) {
if (!MemOpChains.empty())
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains);
}
if (!isTailCall)
Chain = DAG.getCALLSEQ_START(Chain, DAG.getConstant(NumBytes,
getPointerTy(), true),
dl);
if (!isTailCall) {
SDValue C = DAG.getConstant(NumBytes, getPointerTy(), true);
Chain = DAG.getCALLSEQ_START(Chain, C, dl);
}
// Build a sequence of copy-to-reg nodes chained together with token
// chain and flag operands which copy the outgoing args into registers.
@ -553,10 +550,9 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
RegsToPass[i].second, InFlag);
InFlag = Chain.getValue(1);
}
}
// For tail calls lower the arguments to the 'real' stack slot.
if (isTailCall) {
} else {
// For tail calls lower the arguments to the 'real' stack slot.
//
// Force all the incoming stack arguments to be loaded from the stack
// before any new outgoing arguments are stored to the stack, because the
// outgoing stack slots may alias the incoming argument stack slots, and
@ -571,7 +567,7 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
RegsToPass[i].second, InFlag);
InFlag = Chain.getValue(1);
}
InFlag =SDValue();
InFlag = SDValue();
}
// If the callee is a GlobalAddress/ExternalSymbol node (quite common, every
@ -580,8 +576,7 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
if (flag_aligned_memcpy) {
const char *MemcpyName =
"__hexagon_memcpy_likely_aligned_min32bytes_mult8bytes";
Callee =
DAG.getTargetExternalSymbol(MemcpyName, getPointerTy());
Callee = DAG.getTargetExternalSymbol(MemcpyName, getPointerTy());
flag_aligned_memcpy = false;
} else if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, getPointerTy());
@ -603,9 +598,8 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
RegsToPass[i].second.getValueType()));
}
if (InFlag.getNode()) {
if (InFlag.getNode())
Ops.push_back(InFlag);
}
if (isTailCall)
return DAG.getNode(HexagonISD::TC_RETURN, dl, NodeTys, Ops);
@ -630,7 +624,7 @@ static bool getIndexedAddressParts(SDNode *Ptr, EVT VT,
SDValue &Offset, bool &isInc,
SelectionDAG &DAG) {
if (Ptr->getOpcode() != ISD::ADD)
return false;
return false;
if (VT == MVT::i64 || VT == MVT::i32 || VT == MVT::i16 || VT == MVT::i8) {
isInc = (Ptr->getOpcode() == ISD::ADD);
@ -702,8 +696,7 @@ SDValue HexagonTargetLowering::LowerINLINEASM(SDValue Op,
SelectionDAG &DAG) const {
SDNode *Node = Op.getNode();
MachineFunction &MF = DAG.getMachineFunction();
HexagonMachineFunctionInfo *FuncInfo =
MF.getInfo<HexagonMachineFunctionInfo>();
auto &FuncInfo = *MF.getInfo<HexagonMachineFunctionInfo>();
switch (Node->getOpcode()) {
case ISD::INLINEASM: {
unsigned NumOps = Node->getNumOperands();
@ -711,7 +704,7 @@ SDValue HexagonTargetLowering::LowerINLINEASM(SDValue Op,
--NumOps; // Ignore the flag operand.
for (unsigned i = InlineAsm::Op_FirstOperand; i != NumOps;) {
if (FuncInfo->hasClobberLR())
if (FuncInfo.hasClobberLR())
break;
unsigned Flags =
cast<ConstantSDNode>(Node->getOperand(i))->getZExtValue();
@ -736,7 +729,7 @@ SDValue HexagonTargetLowering::LowerINLINEASM(SDValue Op,
// Check it to be lr
const HexagonRegisterInfo *QRI = Subtarget->getRegisterInfo();
if (Reg == QRI->getRARegister()) {
FuncInfo->setHasClobberLR(true);
FuncInfo.setHasClobberLR(true);
break;
}
}
@ -795,43 +788,28 @@ HexagonTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
SelectionDAG &DAG) const {
SDValue Chain = Op.getOperand(0);
SDValue Size = Op.getOperand(1);
SDValue Align = Op.getOperand(2);
SDLoc dl(Op);
unsigned SPReg = getStackPointerRegisterToSaveRestore();
ConstantSDNode *AlignConst = dyn_cast<ConstantSDNode>(Align);
assert(AlignConst && "Non-constant Align in LowerDYNAMIC_STACKALLOC");
// Get a reference to the stack pointer.
SDValue StackPointer = DAG.getCopyFromReg(Chain, dl, SPReg, MVT::i32);
unsigned A = AlignConst->getSExtValue();
auto &HST = static_cast<const HexagonSubtarget&>(DAG.getSubtarget());
auto &HFI = *HST.getFrameLowering();
// "Zero" means natural stack alignment.
if (A == 0)
A = HFI.getStackAlignment();
// Subtract the dynamic size from the actual stack size to
// obtain the new stack size.
SDValue Sub = DAG.getNode(ISD::SUB, dl, MVT::i32, StackPointer, Size);
DEBUG({
dbgs () << __func__ << " Align: " << A << " Size: ";
Size.getNode()->dump(&DAG);
dbgs() << "\n";
});
//
// For Hexagon, the outgoing memory arguments area should be on top of the
// alloca area on the stack i.e., the outgoing memory arguments should be
// at a lower address than the alloca area. Move the alloca area down the
// stack by adding back the space reserved for outgoing arguments to SP
// here.
//
// We do not know what the size of the outgoing args is at this point.
// So, we add a pseudo instruction ADJDYNALLOC that will adjust the
// stack pointer. We patch this instruction with the correct, known
// offset in emitPrologue().
//
// Use a placeholder immediate (zero) for now. This will be patched up
// by emitPrologue().
SDValue ArgAdjust = DAG.getNode(HexagonISD::ADJDYNALLOC, dl,
MVT::i32,
Sub,
DAG.getConstant(0, MVT::i32));
// The Sub result contains the new stack start address, so it
// must be placed in the stack pointer register.
const HexagonRegisterInfo *QRI = Subtarget->getRegisterInfo();
SDValue CopyChain = DAG.getCopyToReg(Chain, dl, QRI->getStackRegister(), Sub);
SDValue Ops[2] = { ArgAdjust, CopyChain };
return DAG.getMergeValues(Ops, dl);
SDValue AC = DAG.getConstant(A, MVT::i32);
SDVTList VTs = DAG.getVTList(MVT::i32, MVT::Other);
return DAG.getNode(HexagonISD::ALLOCA, dl, VTs, Chain, Size, AC);
}
SDValue
@ -847,9 +825,7 @@ const {
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo *MFI = MF.getFrameInfo();
MachineRegisterInfo &RegInfo = MF.getRegInfo();
HexagonMachineFunctionInfo *FuncInfo =
MF.getInfo<HexagonMachineFunctionInfo>();
auto &FuncInfo = *MF.getInfo<HexagonMachineFunctionInfo>();
// Assign locations to all of the incoming arguments.
SmallVector<CCValAssign, 16> ArgLocs;
@ -938,7 +914,7 @@ const {
HEXAGON_LRFP_SIZE +
CCInfo.getNextStackOffset(),
true);
FuncInfo->setVarArgsFrameIndex(FrameIndex);
FuncInfo.setVarArgsFrameIndex(FrameIndex);
}
return Chain;
@ -1795,7 +1771,7 @@ HexagonTargetLowering::getTargetNodeName(unsigned Opcode) const {
case HexagonISD::CONST32: return "HexagonISD::CONST32";
case HexagonISD::CONST32_GP: return "HexagonISD::CONST32_GP";
case HexagonISD::CONST32_Int_Real: return "HexagonISD::CONST32_Int_Real";
case HexagonISD::ADJDYNALLOC: return "HexagonISD::ADJDYNALLOC";
case HexagonISD::ALLOCA: return "HexagonISD::ALLOCA";
case HexagonISD::CMPICC: return "HexagonISD::CMPICC";
case HexagonISD::CMPFCC: return "HexagonISD::CMPFCC";
case HexagonISD::BRICC: return "HexagonISD::BRICC";
@ -2419,20 +2395,14 @@ HexagonTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
}
}
//===----------------------------------------------------------------------===//
// Hexagon Scheduler Hooks
//===----------------------------------------------------------------------===//
MachineBasicBlock *
HexagonTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
MachineBasicBlock *BB)
const {
const {
switch (MI->getOpcode()) {
case Hexagon::ADJDYNALLOC: {
case Hexagon::ALLOCA: {
MachineFunction *MF = BB->getParent();
HexagonMachineFunctionInfo *FuncInfo =
MF->getInfo<HexagonMachineFunctionInfo>();
auto *FuncInfo = MF->getInfo<HexagonMachineFunctionInfo>();
FuncInfo->addAllocaAdjustInst(MI);
return BB;
}

View File

@ -34,7 +34,7 @@ bool isPositiveHalfWord(SDNode *N);
CONST32_Int_Real,
FCONST32,
SETCC,
ADJDYNALLOC,
ALLOCA,
ARGEXTEND,
PIC_ADD,

View File

@ -573,6 +573,12 @@ HexagonInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const {
unsigned Opc = MI->getOpcode();
switch (Opc) {
case Hexagon::ALIGNA:
BuildMI(MBB, MI, DL, get(Hexagon::A2_andir), MI->getOperand(0).getReg())
.addReg(TRI.getFrameRegister())
.addImm(-MI->getOperand(1).getImm());
MBB.erase(MI);
return true;
case Hexagon::TFR_PdTrue: {
unsigned Reg = MI->getOperand(0).getReg();
BuildMI(MBB, MI, DL, get(Hexagon::C2_orn), Reg)

View File

@ -4526,10 +4526,18 @@ def Y2_barrier : SYSInst<(outs), (ins),
// SYSTEM/SUPER -
//===----------------------------------------------------------------------===//
// Generate frameindex addresses.
// Generate frameindex addresses. The main reason for the offset operand is
// that every instruction that is allowed to have frame index as an operand
// will then have that operand followed by an immediate operand (the offset).
// This simplifies the frame-index elimination code.
//
let isMoveImm = 1, isAsCheapAsAMove = 1, isReMaterializable = 1,
isPseudo = 1, isCodeGenOnly = 1, hasSideEffects = 0 in
def TFR_FI: ALU32_ri<(outs IntRegs:$Rd), (ins IntRegs:$fi, s32Imm:$Off), "">;
isPseudo = 1, isCodeGenOnly = 1, hasSideEffects = 0 in {
def TFR_FI : ALU32_ri<(outs IntRegs:$Rd),
(ins IntRegs:$fi, s32Imm:$off), "">;
def TFR_FIA : ALU32_ri<(outs IntRegs:$Rd),
(ins IntRegs:$Rs, IntRegs:$fi, s32Imm:$off), "">;
}
//===----------------------------------------------------------------------===//
// CRUSER - Type.
@ -5105,21 +5113,25 @@ def : Pat <(mulhu (i64 DoubleRegs:$src1), (i64 DoubleRegs:$src2)),
)>;
// Hexagon specific ISD nodes.
def SDTHexagonADJDYNALLOC : SDTypeProfile<1, 2, [SDTCisVT<0, i32>,
SDTCisVT<1, i32>]>;
def SDTHexagonARGEXTEND : SDTypeProfile<1, 1, [SDTCisVT<0, i32>]>;
def SDTHexagonALLOCA : SDTypeProfile<1, 2,
[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>;
def HexagonALLOCA : SDNode<"HexagonISD::ALLOCA", SDTHexagonALLOCA,
[SDNPHasChain]>;
def Hexagon_ADJDYNALLOC : SDNode<"HexagonISD::ADJDYNALLOC",
SDTHexagonADJDYNALLOC>;
def Hexagon_ARGEXTEND : SDNode<"HexagonISD::ARGEXTEND", SDTHexagonARGEXTEND>;
// The reason for the custom inserter is to record all ALLOCA instructions
// in MachineFunctionInfo.
let Defs = [R29], isCodeGenOnly = 1, isPseudo = 1, hasSideEffects = 1,
usesCustomInserter = 1 in
def ALLOCA: ALU32Inst<(outs IntRegs:$Rd),
(ins IntRegs:$Rs, u32Imm:$A), "",
[(set (i32 IntRegs:$Rd),
(HexagonALLOCA (i32 IntRegs:$Rs), (i32 imm:$A)))]>;
// Needed to tag these instructions for stack layout.
let isCodeGenOnly = 1, usesCustomInserter = 1 in
def ADJDYNALLOC : T_Addri<s6Imm>;
def: Pat<(Hexagon_ADJDYNALLOC I32:$Rs, s16ImmPred:$s16),
(ADJDYNALLOC I32:$Rs, imm:$s16)>;
let isCodeGenOnly = 1, isPseudo = 1, Uses = [R30], hasSideEffects = 0 in
def ALIGNA : ALU32Inst<(outs IntRegs:$Rd), (ins u32Imm:$A), "", []>;
def SDTHexagonARGEXTEND : SDTypeProfile<1, 1, [SDTCisVT<0, i32>]>;
def Hexagon_ARGEXTEND : SDNode<"HexagonISD::ARGEXTEND", SDTHexagonARGEXTEND>;
let isCodeGenOnly = 1 in
def ARGEXTEND : ALU32_rr <(outs IntRegs:$dst), (ins IntRegs:$src1),
"$dst = $src1",

View File

@ -27,6 +27,7 @@ class HexagonMachineFunctionInfo : public MachineFunctionInfo {
// returning the value of the returned struct in a register. This field
// holds the virtual register into which the sret argument is passed.
unsigned SRetReturnReg;
unsigned StackAlignBaseReg;
std::vector<MachineInstr*> AllocaAdjustInsts;
int VarArgsFrameIndex;
bool HasClobberLR;
@ -35,10 +36,11 @@ class HexagonMachineFunctionInfo : public MachineFunctionInfo {
virtual void anchor();
public:
HexagonMachineFunctionInfo() : SRetReturnReg(0), HasClobberLR(0),
HasEHReturn(false) {}
HexagonMachineFunctionInfo() : SRetReturnReg(0), StackAlignBaseReg(0),
HasClobberLR(0), HasEHReturn(false) {}
HexagonMachineFunctionInfo(MachineFunction &MF) : SRetReturnReg(0),
StackAlignBaseReg(0),
HasClobberLR(0),
HasEHReturn(false) {}
@ -74,6 +76,9 @@ public:
bool hasEHReturn() const { return HasEHReturn; };
void setHasEHReturn(bool H = true) { HasEHReturn = H; };
void setStackAlignBaseVReg(unsigned R) { StackAlignBaseReg = R; }
unsigned getStackAlignBaseVReg() const { return StackAlignBaseReg; }
};
} // End llvm namespace

View File

@ -30,7 +30,9 @@
#include "llvm/IR/Type.h"
#include "llvm/MC/MachineLocation.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
@ -40,6 +42,37 @@ using namespace llvm;
HexagonRegisterInfo::HexagonRegisterInfo()
: HexagonGenRegisterInfo(Hexagon::R31) {}
bool HexagonRegisterInfo::isEHReturnCalleeSaveReg(unsigned R) const {
return R == Hexagon::R0 || R == Hexagon::R1 || R == Hexagon::R2 ||
R == Hexagon::R3 || R == Hexagon::D0 || R == Hexagon::D1;
}
bool HexagonRegisterInfo::isCalleeSaveReg(unsigned Reg) const {
return Hexagon::R16 <= Reg && Reg <= Hexagon::R27;
}
const MCPhysReg *
HexagonRegisterInfo::getCallerSavedRegs(const MachineFunction *MF) const {
static const MCPhysReg CallerSavedRegsV4[] = {
Hexagon::R0, Hexagon::R1, Hexagon::R2, Hexagon::R3, Hexagon::R4,
Hexagon::R5, Hexagon::R6, Hexagon::R7, Hexagon::R8, Hexagon::R9,
Hexagon::R10, Hexagon::R11, Hexagon::R12, Hexagon::R13, Hexagon::R14,
Hexagon::R15, 0
};
auto &HST = static_cast<const HexagonSubtarget&>(MF->getSubtarget());
switch (HST.getHexagonArchVersion()) {
case HexagonSubtarget::V4:
case HexagonSubtarget::V5:
return CallerSavedRegsV4;
}
llvm_unreachable(
"Callee saved registers requested for unknown archtecture version");
}
const MCPhysReg *
HexagonRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
static const MCPhysReg CalleeSavedRegsV3[] = {
@ -75,173 +108,153 @@ BitVector HexagonRegisterInfo::getReservedRegs(const MachineFunction &MF)
}
const TargetRegisterClass* const*
HexagonRegisterInfo::getCalleeSavedRegClasses(const MachineFunction *MF) const {
static const TargetRegisterClass * const CalleeSavedRegClassesV3[] = {
&Hexagon::IntRegsRegClass, &Hexagon::IntRegsRegClass,
&Hexagon::IntRegsRegClass, &Hexagon::IntRegsRegClass,
&Hexagon::IntRegsRegClass, &Hexagon::IntRegsRegClass,
&Hexagon::IntRegsRegClass, &Hexagon::IntRegsRegClass,
&Hexagon::IntRegsRegClass, &Hexagon::IntRegsRegClass,
&Hexagon::IntRegsRegClass, &Hexagon::IntRegsRegClass,
};
switch (MF->getSubtarget<HexagonSubtarget>().getHexagonArchVersion()) {
case HexagonSubtarget::V4:
case HexagonSubtarget::V5:
return CalleeSavedRegClassesV3;
}
llvm_unreachable("Callee saved register classes requested for unknown "
"architecture version");
}
void HexagonRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
int SPAdj, unsigned FIOperandNum,
int SPAdj, unsigned FIOp,
RegScavenger *RS) const {
//
// Hexagon_TODO: Do we need to enforce this for Hexagon?
assert(SPAdj == 0 && "Unexpected");
MachineInstr &MI = *II;
int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
// Addressable stack objects are accessed using neg. offsets from %fp.
MachineFunction &MF = *MI.getParent()->getParent();
const HexagonInstrInfo &TII =
*static_cast<const HexagonInstrInfo *>(MF.getSubtarget().getInstrInfo());
int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex);
MachineBasicBlock &MB = *MI.getParent();
MachineFunction &MF = *MB.getParent();
MachineFrameInfo &MFI = *MF.getFrameInfo();
auto &HST = static_cast<const HexagonSubtarget&>(MF.getSubtarget());
auto &HII = *HST.getInstrInfo();
auto &HFI = *HST.getFrameLowering();
unsigned FrameReg = getFrameRegister(MF);
const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
if (!TFI->hasFP(MF)) {
int FI = MI.getOperand(FIOp).getIndex();
int Offset = MFI.getObjectOffset(FI) + MI.getOperand(FIOp+1).getImm();
bool HasAlloca = MFI.hasVarSizedObjects();
bool HasAlign = needsStackRealignment(MF);
// XXX: Fixed objects cannot be accessed through SP if there are aligned
// objects in the local frame, or if there are dynamically allocated objects.
// In such cases, there has to be FP available.
if (!HFI.hasFP(MF)) {
assert(!HasAlloca && !HasAlign && "This function must have frame pointer");
// We will not reserve space on the stack for the lr and fp registers.
Offset -= 2 * Hexagon_WordSize;
Offset -= 8;
}
unsigned SP = getStackRegister(), FP = getFrameRegister();
unsigned AP = 0;
if (MachineInstr *AI = HFI.getAlignaInstr(MF))
AP = AI->getOperand(0).getReg();
unsigned FrameSize = MFI.getStackSize();
if (MI.getOpcode() == Hexagon::TFR_FI)
MI.setDesc(TII.get(Hexagon::A2_addi));
if (!MFI.hasVarSizedObjects() &&
TII.isValidOffset(MI.getOpcode(), (FrameSize+Offset)) &&
!TII.isSpillPredRegOp(&MI)) {
// Replace frame index with a stack pointer reference.
MI.getOperand(FIOperandNum).ChangeToRegister(getStackRegister(), false,
false, true);
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(FrameSize+Offset);
// Special handling of dbg_value instructions and INLINEASM.
if (MI.isDebugValue() || MI.isInlineAsm()) {
MI.getOperand(FIOp).ChangeToRegister(SP, false /*isDef*/);
MI.getOperand(FIOp+1).ChangeToImmediate(Offset+FrameSize);
return;
}
bool UseFP = false, UseAP = false; // Default: use SP.
if (MFI.isFixedObjectIndex(FI) || MFI.isObjectPreAllocated(FI)) {
UseFP = HasAlloca || HasAlign;
} else {
// Replace frame index with a frame pointer reference.
if (!TII.isValidOffset(MI.getOpcode(), Offset)) {
// If the offset overflows, then correct it.
//
// For loads, we do not need a reserved register
// r0 = memw(r30 + #10000) to:
//
// r0 = add(r30, #10000)
// r0 = memw(r0)
if ( (MI.getOpcode() == Hexagon::L2_loadri_io) ||
(MI.getOpcode() == Hexagon::L2_loadrd_io) ||
(MI.getOpcode() == Hexagon::L2_loadrh_io) ||
(MI.getOpcode() == Hexagon::L2_loadruh_io) ||
(MI.getOpcode() == Hexagon::L2_loadrb_io) ||
(MI.getOpcode() == Hexagon::L2_loadrub_io)) {
unsigned dstReg = (MI.getOpcode() == Hexagon::L2_loadrd_io) ?
getSubReg(MI.getOperand(0).getReg(), Hexagon::subreg_loreg) :
MI.getOperand(0).getReg();
// Check if offset can fit in addi.
if (!TII.isValidOffset(Hexagon::A2_addi, Offset)) {
BuildMI(*MI.getParent(), II, MI.getDebugLoc(),
TII.get(Hexagon::CONST32_Int_Real), dstReg).addImm(Offset);
BuildMI(*MI.getParent(), II, MI.getDebugLoc(),
TII.get(Hexagon::A2_add),
dstReg).addReg(FrameReg).addReg(dstReg);
} else {
BuildMI(*MI.getParent(), II, MI.getDebugLoc(),
TII.get(Hexagon::A2_addi),
dstReg).addReg(FrameReg).addImm(Offset);
}
MI.getOperand(FIOperandNum).ChangeToRegister(dstReg, false, false,true);
MI.getOperand(FIOperandNum+1).ChangeToImmediate(0);
} else if ((MI.getOpcode() == Hexagon::S2_storeri_io) ||
(MI.getOpcode() == Hexagon::S2_storerd_io) ||
(MI.getOpcode() == Hexagon::S2_storerh_io) ||
(MI.getOpcode() == Hexagon::S2_storerb_io)) {
// For stores, we need a reserved register. Change
// memw(r30 + #10000) = r0 to:
//
// rs = add(r30, #10000);
// memw(rs) = r0
unsigned resReg = HEXAGON_RESERVED_REG_1;
// Check if offset can fit in addi.
if (!TII.isValidOffset(Hexagon::A2_addi, Offset)) {
BuildMI(*MI.getParent(), II, MI.getDebugLoc(),
TII.get(Hexagon::CONST32_Int_Real), resReg).addImm(Offset);
BuildMI(*MI.getParent(), II, MI.getDebugLoc(),
TII.get(Hexagon::A2_add),
resReg).addReg(FrameReg).addReg(resReg);
} else {
BuildMI(*MI.getParent(), II, MI.getDebugLoc(),
TII.get(Hexagon::A2_addi),
resReg).addReg(FrameReg).addImm(Offset);
}
MI.getOperand(FIOperandNum).ChangeToRegister(resReg, false, false,true);
MI.getOperand(FIOperandNum+1).ChangeToImmediate(0);
} else if (TII.isMemOp(&MI)) {
// use the constant extender if the instruction provides it
if (TII.isConstExtended(&MI)) {
MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false);
MI.getOperand(FIOperandNum+1).ChangeToImmediate(Offset);
TII.immediateExtend(&MI);
} else {
llvm_unreachable("Need to implement for memops");
}
} else {
unsigned dstReg = MI.getOperand(0).getReg();
BuildMI(*MI.getParent(), II, MI.getDebugLoc(),
TII.get(Hexagon::CONST32_Int_Real), dstReg).addImm(Offset);
BuildMI(*MI.getParent(), II, MI.getDebugLoc(),
TII.get(Hexagon::A2_add),
dstReg).addReg(FrameReg).addReg(dstReg);
// Can we delete MI??? r2 = add (r2, #0).
MI.getOperand(FIOperandNum).ChangeToRegister(dstReg, false, false,true);
MI.getOperand(FIOperandNum+1).ChangeToImmediate(0);
}
} else {
// If the offset is small enough to fit in the immediate field, directly
// encode it.
MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false);
MI.getOperand(FIOperandNum+1).ChangeToImmediate(Offset);
if (HasAlloca) {
if (HasAlign)
UseAP = true;
else
UseFP = true;
}
}
unsigned Opc = MI.getOpcode();
bool ValidSP = HII.isValidOffset(Opc, FrameSize+Offset);
bool ValidFP = HII.isValidOffset(Opc, Offset);
// Calculate the actual offset in the instruction.
int64_t RealOffset = Offset;
if (!UseFP && !UseAP)
RealOffset = FrameSize+Offset;
switch (Opc) {
case Hexagon::TFR_FIA:
MI.setDesc(HII.get(Hexagon::A2_addi));
MI.getOperand(FIOp).ChangeToImmediate(RealOffset);
MI.RemoveOperand(FIOp+1);
return;
case Hexagon::TFR_FI:
// Set up the instruction for updating below.
MI.setDesc(HII.get(Hexagon::A2_addi));
break;
}
unsigned BP = 0;
bool Valid = false;
if (UseFP) {
BP = FP;
Valid = ValidFP;
} else if (UseAP) {
BP = AP;
Valid = ValidFP;
} else {
BP = SP;
Valid = ValidSP;
}
if (Valid) {
MI.getOperand(FIOp).ChangeToRegister(BP, false);
MI.getOperand(FIOp+1).ChangeToImmediate(RealOffset);
return;
}
#ifndef NDEBUG
const Function *F = MF.getFunction();
dbgs() << "In function ";
if (F) dbgs() << F->getName();
else dbgs() << "<?>";
dbgs() << ", BB#" << MB.getNumber() << "\n" << MI;
#endif
llvm_unreachable("Unhandled instruction");
}
unsigned HexagonRegisterInfo::getRARegister() const {
return Hexagon::R31;
}
unsigned HexagonRegisterInfo::getFrameRegister(const MachineFunction
&MF) const {
const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
if (TFI->hasFP(MF)) {
if (TFI->hasFP(MF))
return Hexagon::R30;
}
return Hexagon::R29;
}
unsigned HexagonRegisterInfo::getFrameRegister() const {
return Hexagon::R30;
}
unsigned HexagonRegisterInfo::getStackRegister() const {
return Hexagon::R29;
}
bool
HexagonRegisterInfo::useFPForScavengingIndex(const MachineFunction &MF) const {
return MF.getSubtarget().getFrameLowering()->hasFP(MF);
}
bool
HexagonRegisterInfo::needsStackRealignment(const MachineFunction &MF) const {
const MachineFrameInfo *MFI = MF.getFrameInfo();
return MFI->getMaxAlignment() > 8;
}
unsigned HexagonRegisterInfo::getFirstCallerSavedNonParamReg() const {
return Hexagon::R6;
}
#define GET_REGINFO_TARGET_DESC
#include "HexagonGenRegisterInfo.inc"

View File

@ -43,25 +43,29 @@ struct HexagonRegisterInfo : public HexagonGenRegisterInfo {
/// Code Generation virtual methods...
const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override;
const TargetRegisterClass* const*
getCalleeSavedRegClasses(const MachineFunction *MF = nullptr) const;
BitVector getReservedRegs(const MachineFunction &MF) const override;
void eliminateFrameIndex(MachineBasicBlock::iterator II,
int SPAdj, unsigned FIOperandNum,
RegScavenger *RS = nullptr) const override;
void eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj,
unsigned FIOperandNum, RegScavenger *RS = nullptr) const override;
/// determineFrameLayout - Determine the size of the frame and maximum call
/// frame size.
void determineFrameLayout(MachineFunction &MF) const;
/// requiresRegisterScavenging - returns true since we may need scavenging for
/// a temporary register when generating hardware loop instructions.
/// Returns true since we may need scavenging for a temporary register
/// when generating hardware loop instructions.
bool requiresRegisterScavenging(const MachineFunction &MF) const override {
return true;
}
/// Returns true. Spill code for predicate registers might need an extra
/// register.
bool requiresFrameIndexScavenging(const MachineFunction &MF) const override {
return true;
}
bool needsStackRealignment(const MachineFunction &MF) const override;
/// Returns true if the frame pointer is valid.
bool useFPForScavengingIndex(const MachineFunction &MF) const override;
bool trackLivenessAfterRegAlloc(const MachineFunction &MF) const override {
return true;
}
@ -71,6 +75,12 @@ struct HexagonRegisterInfo : public HexagonGenRegisterInfo {
unsigned getFrameRegister(const MachineFunction &MF) const override;
unsigned getFrameRegister() const;
unsigned getStackRegister() const;
const uint16_t *getCallerSavedRegs(const MachineFunction *MF) const;
unsigned getFirstCallerSavedNonParamReg() const;
bool isEHReturnCalleeSaveReg(unsigned Reg) const;
bool isCalleeSaveReg(unsigned Reg) const;
};
} // end namespace llvm