158 changes: 64 additions & 94 deletions llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {
Expand All @@ -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:
Expand All @@ -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.
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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());
Expand All @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -702,16 +696,15 @@ 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();
if (Node->getOperand(NumOps-1).getValueType() == MVT::Glue)
--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();
Expand All @@ -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;
}
}
Expand Down Expand Up @@ -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();

// Get a reference to the stack pointer.
SDValue StackPointer = DAG.getCopyFromReg(Chain, dl, SPReg, MVT::i32);

// 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);

//
// 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);
ConstantSDNode *AlignConst = dyn_cast<ConstantSDNode>(Align);
assert(AlignConst && "Non-constant Align in LowerDYNAMIC_STACKALLOC");

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();

DEBUG({
dbgs () << __func__ << " Align: " << A << " Size: ";
Size.getNode()->dump(&DAG);
dbgs() << "\n";
});

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
Expand All @@ -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;
Expand Down Expand Up @@ -938,7 +914,7 @@ const {
HEXAGON_LRFP_SIZE +
CCInfo.getNextStackOffset(),
true);
FuncInfo->setVarArgsFrameIndex(FrameIndex);
FuncInfo.setVarArgsFrameIndex(FrameIndex);
}

return Chain;
Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/Hexagon/HexagonISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ bool isPositiveHalfWord(SDNode *N);
CONST32_Int_Real,
FCONST32,
SETCC,
ADJDYNALLOC,
ALLOCA,
ARGEXTEND,

PIC_ADD,
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
48 changes: 30 additions & 18 deletions llvm/lib/Target/Hexagon/HexagonInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 Hexagon_ADJDYNALLOC : SDNode<"HexagonISD::ADJDYNALLOC",
SDTHexagonADJDYNALLOC>;
def Hexagon_ARGEXTEND : SDNode<"HexagonISD::ARGEXTEND", SDTHexagonARGEXTEND>;

// 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)>;

def SDTHexagonALLOCA : SDTypeProfile<1, 2,
[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>;
def HexagonALLOCA : SDNode<"HexagonISD::ALLOCA", SDTHexagonALLOCA,
[SDNPHasChain]>;

// 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)))]>;

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",
Expand Down
9 changes: 7 additions & 2 deletions llvm/lib/Target/Hexagon/HexagonMachineFunctionInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {}

Expand Down Expand Up @@ -74,6 +76,9 @@ class HexagonMachineFunctionInfo : public MachineFunctionInfo {

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

Expand Down
271 changes: 142 additions & 129 deletions llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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[] = {
Expand Down Expand Up @@ -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"
32 changes: 21 additions & 11 deletions llvm/lib/Target/Hexagon/HexagonRegisterInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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
Expand Down