forked from OSchip/llvm-project
[Hexagon] Add target feature to generate long calls
llvm-svn: 276638
This commit is contained in:
parent
8031238017
commit
080bebd212
|
@ -27,11 +27,12 @@ def ArchV5: SubtargetFeature<"v5", "HexagonArchVersion", "V5", "Hexagon V5">;
|
|||
def ArchV55: SubtargetFeature<"v55", "HexagonArchVersion", "V55", "Hexagon V55">;
|
||||
def ArchV60: SubtargetFeature<"v60", "HexagonArchVersion", "V60", "Hexagon V60">;
|
||||
|
||||
// Hexagon ISA Extensions
|
||||
def ExtensionHVX: SubtargetFeature<"hvx", "UseHVXOps",
|
||||
"true", "Hexagon HVX instructions">;
|
||||
def ExtensionHVXDbl: SubtargetFeature<"hvx-double", "UseHVXDblOps",
|
||||
"true", "Hexagon HVX Double instructions">;
|
||||
def FeatureHVX: SubtargetFeature<"hvx", "UseHVXOps", "true",
|
||||
"Hexagon HVX instructions">;
|
||||
def FeatureHVXDbl: SubtargetFeature<"hvx-double", "UseHVXDblOps", "true",
|
||||
"Hexagon HVX Double instructions">;
|
||||
def FeatureLongCalls: SubtargetFeature<"long-calls", "UseLongCalls", "true",
|
||||
"Use constant-extended calls">;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Hexagon Instruction Predicate Definitions.
|
||||
|
@ -45,10 +46,10 @@ def HasV60T : Predicate<"HST->hasV60TOps()">,
|
|||
def UseMEMOP : Predicate<"HST->useMemOps()">;
|
||||
def IEEERndNearV5T : Predicate<"HST->modeIEEERndNear()">;
|
||||
def UseHVXDbl : Predicate<"HST->useHVXDblOps()">,
|
||||
AssemblerPredicate<"ExtensionHVXDbl">;
|
||||
AssemblerPredicate<"FeatureHVXDbl">;
|
||||
def UseHVXSgl : Predicate<"HST->useHVXSglOps()">;
|
||||
def UseHVX : Predicate<"HST->useHVXSglOps() ||HST->useHVXDblOps()">,
|
||||
AssemblerPredicate<"ExtensionHVX">;
|
||||
AssemblerPredicate<"FeatureHVX">;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Classes used for relation maps.
|
||||
|
@ -269,7 +270,7 @@ def : Proc<"hexagonv5", HexagonModelV4,
|
|||
def : Proc<"hexagonv55", HexagonModelV55,
|
||||
[ArchV4, ArchV5, ArchV55]>;
|
||||
def : Proc<"hexagonv60", HexagonModelV60,
|
||||
[ArchV4, ArchV5, ArchV55, ArchV60, ExtensionHVX]>;
|
||||
[ArchV4, ArchV5, ArchV55, ArchV60, FeatureHVX]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Declare the target which we are implementing
|
||||
|
|
|
@ -149,6 +149,10 @@ static cl::opt<unsigned> ShrinkLimit("shrink-frame-limit", cl::init(UINT_MAX),
|
|||
cl::Hidden, cl::ZeroOrMore, cl::desc("Max count of stack frame "
|
||||
"shrink-wraps"));
|
||||
|
||||
static cl::opt<bool> EnableSaveRestoreLong("enable-save-restore-long",
|
||||
cl::Hidden, cl::desc("Enable long calls for save-restore stubs."),
|
||||
cl::init(false), cl::ZeroOrMore);
|
||||
|
||||
static cl::opt<bool> UseAllocframe("use-allocframe", cl::init(true),
|
||||
cl::Hidden, cl::desc("Use allocframe more conservatively"));
|
||||
|
||||
|
@ -342,7 +346,7 @@ void HexagonFrameLowering::findShrunkPrologEpilog(MachineFunction &MF,
|
|||
ShrinkCounter++;
|
||||
}
|
||||
|
||||
auto &HST = static_cast<const HexagonSubtarget&>(MF.getSubtarget());
|
||||
auto &HST = MF.getSubtarget<HexagonSubtarget>();
|
||||
auto &HRI = *HST.getRegisterInfo();
|
||||
|
||||
MachineDominatorTree MDT;
|
||||
|
@ -440,7 +444,7 @@ void HexagonFrameLowering::findShrunkPrologEpilog(MachineFunction &MF,
|
|||
/// in one place allows shrink-wrapping of the stack frame.
|
||||
void HexagonFrameLowering::emitPrologue(MachineFunction &MF,
|
||||
MachineBasicBlock &MBB) const {
|
||||
auto &HST = static_cast<const HexagonSubtarget&>(MF.getSubtarget());
|
||||
auto &HST = MF.getSubtarget<HexagonSubtarget>();
|
||||
auto &HRI = *HST.getRegisterInfo();
|
||||
|
||||
MachineFrameInfo *MFI = MF.getFrameInfo();
|
||||
|
@ -581,7 +585,7 @@ void HexagonFrameLowering::insertEpilogueInBlock(MachineBasicBlock &MBB) const {
|
|||
if (!hasFP(MF))
|
||||
return;
|
||||
|
||||
auto &HST = static_cast<const HexagonSubtarget&>(MF.getSubtarget());
|
||||
auto &HST = MF.getSubtarget<HexagonSubtarget>();
|
||||
auto &HII = *HST.getInstrInfo();
|
||||
auto &HRI = *HST.getRegisterInfo();
|
||||
unsigned SP = HRI.getStackRegister();
|
||||
|
@ -1049,7 +1053,8 @@ bool HexagonFrameLowering::insertCSRSpillsInBlock(MachineBasicBlock &MBB,
|
|||
MachineBasicBlock::iterator MI = MBB.begin();
|
||||
PrologueStubs = false;
|
||||
MachineFunction &MF = *MBB.getParent();
|
||||
auto &HII = *MF.getSubtarget<HexagonSubtarget>().getInstrInfo();
|
||||
auto &HST = MF.getSubtarget<HexagonSubtarget>();
|
||||
auto &HII = *HST.getInstrInfo();
|
||||
|
||||
if (useSpillFunction(MF, CSI)) {
|
||||
PrologueStubs = true;
|
||||
|
@ -1059,20 +1064,31 @@ bool HexagonFrameLowering::insertCSRSpillsInBlock(MachineBasicBlock &MBB,
|
|||
StkOvrFlowEnabled);
|
||||
auto &HTM = static_cast<const HexagonTargetMachine&>(MF.getTarget());
|
||||
bool IsPIC = HTM.isPositionIndependent();
|
||||
bool LongCalls = HST.useLongCalls() || EnableSaveRestoreLong;
|
||||
|
||||
// Call spill function.
|
||||
DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc() : DebugLoc();
|
||||
unsigned SpillOpc;
|
||||
if (StkOvrFlowEnabled)
|
||||
SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4STK_PIC
|
||||
: Hexagon::SAVE_REGISTERS_CALL_V4STK;
|
||||
else
|
||||
SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4_PIC
|
||||
: Hexagon::SAVE_REGISTERS_CALL_V4;
|
||||
if (StkOvrFlowEnabled) {
|
||||
if (LongCalls)
|
||||
SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4STK_EXT_PIC
|
||||
: Hexagon::SAVE_REGISTERS_CALL_V4STK_EXT;
|
||||
else
|
||||
SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4STK_PIC
|
||||
: Hexagon::SAVE_REGISTERS_CALL_V4STK;
|
||||
} else {
|
||||
if (LongCalls)
|
||||
SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4_EXT_PIC
|
||||
: Hexagon::SAVE_REGISTERS_CALL_V4_EXT;
|
||||
else
|
||||
SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4_PIC
|
||||
: Hexagon::SAVE_REGISTERS_CALL_V4;
|
||||
}
|
||||
|
||||
MachineInstr *SaveRegsCall =
|
||||
BuildMI(MBB, MI, DL, HII.get(SpillOpc))
|
||||
.addExternalSymbol(SpillFun);
|
||||
|
||||
// Add callee-saved registers as use.
|
||||
addCalleeSaveRegistersAsImpOperand(SaveRegsCall, CSI, false, true);
|
||||
// Add live in registers.
|
||||
|
@ -1104,7 +1120,8 @@ bool HexagonFrameLowering::insertCSRRestoresInBlock(MachineBasicBlock &MBB,
|
|||
|
||||
MachineBasicBlock::iterator MI = MBB.getFirstTerminator();
|
||||
MachineFunction &MF = *MBB.getParent();
|
||||
auto &HII = *MF.getSubtarget<HexagonSubtarget>().getInstrInfo();
|
||||
auto &HST = MF.getSubtarget<HexagonSubtarget>();
|
||||
auto &HII = *HST.getInstrInfo();
|
||||
|
||||
if (useRestoreFunction(MF, CSI)) {
|
||||
bool HasTC = hasTailCall(MBB) || !hasReturn(MBB);
|
||||
|
@ -1113,6 +1130,7 @@ bool HexagonFrameLowering::insertCSRRestoresInBlock(MachineBasicBlock &MBB,
|
|||
const char *RestoreFn = getSpillFunctionFor(MaxR, Kind);
|
||||
auto &HTM = static_cast<const HexagonTargetMachine&>(MF.getTarget());
|
||||
bool IsPIC = HTM.isPositionIndependent();
|
||||
bool LongCalls = HST.useLongCalls() || EnableSaveRestoreLong;
|
||||
|
||||
// Call spill function.
|
||||
DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc()
|
||||
|
@ -1120,17 +1138,27 @@ bool HexagonFrameLowering::insertCSRRestoresInBlock(MachineBasicBlock &MBB,
|
|||
MachineInstr *DeallocCall = nullptr;
|
||||
|
||||
if (HasTC) {
|
||||
unsigned ROpc = IsPIC ? Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC
|
||||
: Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4;
|
||||
DeallocCall = BuildMI(MBB, MI, DL, HII.get(ROpc))
|
||||
unsigned RetOpc;
|
||||
if (LongCalls)
|
||||
RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT_PIC
|
||||
: Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT;
|
||||
else
|
||||
RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC
|
||||
: Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4;
|
||||
DeallocCall = BuildMI(MBB, MI, DL, HII.get(RetOpc))
|
||||
.addExternalSymbol(RestoreFn);
|
||||
} else {
|
||||
// The block has a return.
|
||||
MachineBasicBlock::iterator It = MBB.getFirstTerminator();
|
||||
assert(It->isReturn() && std::next(It) == MBB.end());
|
||||
unsigned ROpc = IsPIC ? Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC
|
||||
: Hexagon::RESTORE_DEALLOC_RET_JMP_V4;
|
||||
DeallocCall = BuildMI(MBB, It, DL, HII.get(ROpc))
|
||||
unsigned RetOpc;
|
||||
if (LongCalls)
|
||||
RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT_PIC
|
||||
: Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT;
|
||||
else
|
||||
RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC
|
||||
: Hexagon::RESTORE_DEALLOC_RET_JMP_V4;
|
||||
DeallocCall = BuildMI(MBB, It, DL, HII.get(RetOpc))
|
||||
.addExternalSymbol(RestoreFn);
|
||||
// Transfer the function live-out registers.
|
||||
DeallocCall->copyImplicitOps(MF, *It);
|
||||
|
|
|
@ -842,14 +842,17 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
|
|||
InFlag = SDValue();
|
||||
}
|
||||
|
||||
bool LongCalls = MF.getSubtarget<HexagonSubtarget>().useLongCalls();
|
||||
unsigned Flags = LongCalls ? HexagonII::HMOTF_ConstExtended : 0;
|
||||
|
||||
// If the callee is a GlobalAddress/ExternalSymbol node (quite common, every
|
||||
// direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol
|
||||
// node so that legalize doesn't hack it.
|
||||
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
|
||||
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, PtrVT);
|
||||
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, PtrVT, 0, Flags);
|
||||
} else if (ExternalSymbolSDNode *S =
|
||||
dyn_cast<ExternalSymbolSDNode>(Callee)) {
|
||||
Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT);
|
||||
Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, Flags);
|
||||
}
|
||||
|
||||
// Returns a chain & a flag for retval copy to use.
|
||||
|
|
|
@ -44,14 +44,17 @@ SDValue HexagonSelectionDAGInfo::EmitTargetCodeForMemcpy(
|
|||
|
||||
const char *SpecialMemcpyName =
|
||||
"__hexagon_memcpy_likely_aligned_min32bytes_mult8bytes";
|
||||
const MachineFunction &MF = DAG.getMachineFunction();
|
||||
bool LongCalls = MF.getSubtarget<HexagonSubtarget>().useLongCalls();
|
||||
unsigned Flags = LongCalls ? HexagonII::HMOTF_ConstExtended : 0;
|
||||
|
||||
TargetLowering::CallLoweringInfo CLI(DAG);
|
||||
CLI.setDebugLoc(dl)
|
||||
.setChain(Chain)
|
||||
.setCallee(TLI.getLibcallCallingConv(RTLIB::MEMCPY),
|
||||
Type::getVoidTy(*DAG.getContext()),
|
||||
DAG.getTargetExternalSymbol(
|
||||
SpecialMemcpyName, TLI.getPointerTy(DAG.getDataLayout())),
|
||||
DAG.getTargetExternalSymbol(SpecialMemcpyName,
|
||||
TLI.getPointerTy(DAG.getDataLayout()), Flags),
|
||||
std::move(Args))
|
||||
.setDiscardResult();
|
||||
|
||||
|
|
|
@ -69,6 +69,10 @@ static cl::opt<bool> EnableSubregLiveness("hexagon-subreg-liveness",
|
|||
cl::Hidden, cl::ZeroOrMore, cl::init(false),
|
||||
cl::desc("Enable subregister liveness tracking for Hexagon"));
|
||||
|
||||
static cl::opt<bool> OverrideLongCalls("hexagon-long-calls",
|
||||
cl::Hidden, cl::ZeroOrMore, cl::init(false),
|
||||
cl::desc("If present, forces/disables the use of long calls"));
|
||||
|
||||
void HexagonSubtarget::initializeEnvironment() {
|
||||
UseMemOps = false;
|
||||
ModeIEEERndNear = false;
|
||||
|
@ -94,12 +98,15 @@ HexagonSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) {
|
|||
|
||||
UseHVXOps = false;
|
||||
UseHVXDblOps = false;
|
||||
UseLongCalls = false;
|
||||
ParseSubtargetFeatures(CPUString, FS);
|
||||
|
||||
if (EnableHexagonHVX.getPosition())
|
||||
UseHVXOps = EnableHexagonHVX;
|
||||
if (EnableHexagonHVXDouble.getPosition())
|
||||
UseHVXDblOps = EnableHexagonHVXDouble;
|
||||
if (OverrideLongCalls.getPosition())
|
||||
UseLongCalls = OverrideLongCalls;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ class HexagonSubtarget : public HexagonGenSubtargetInfo {
|
|||
virtual void anchor();
|
||||
|
||||
bool UseMemOps, UseHVXOps, UseHVXDblOps;
|
||||
bool UseLongCalls;
|
||||
bool ModeIEEERndNear;
|
||||
|
||||
public:
|
||||
|
@ -101,6 +102,7 @@ public:
|
|||
bool useHVXOps() const { return UseHVXOps; }
|
||||
bool useHVXDblOps() const { return UseHVXOps && UseHVXDblOps; }
|
||||
bool useHVXSglOps() const { return UseHVXOps && !UseHVXDblOps; }
|
||||
bool useLongCalls() const { return UseLongCalls; }
|
||||
|
||||
bool useBSBScheduling() const { return UseBSBScheduling; }
|
||||
bool enableMachineScheduler() const override;
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
; RUN: llc -march=hexagon -enable-save-restore-long < %s | FileCheck %s
|
||||
|
||||
; Check that the -long-calls feature is supported by the backend.
|
||||
|
||||
; CHECK: call ##foo
|
||||
; CHECK: jump ##__restore
|
||||
define i64 @test_longcall(i32 %x, i32 %y) #0 {
|
||||
entry:
|
||||
%add = add nsw i32 %x, 5
|
||||
%call = tail call i64 @foo(i32 %add) #6
|
||||
%conv = sext i32 %y to i64
|
||||
%add1 = add nsw i64 %call, %conv
|
||||
ret i64 %add1
|
||||
}
|
||||
|
||||
; CHECK: jump ##foo
|
||||
define i64 @test_longtailcall(i32 %x, i32 %y) #1 {
|
||||
entry:
|
||||
%add = add nsw i32 %x, 5
|
||||
%call = tail call i64 @foo(i32 %add) #6
|
||||
ret i64 %call
|
||||
}
|
||||
|
||||
; CHECK: call ##bar
|
||||
define i64 @test_longnoret(i32 %x, i32 %y) #2 {
|
||||
entry:
|
||||
%add = add nsw i32 %x, 5
|
||||
%0 = tail call i64 @bar(i32 %add) #7
|
||||
unreachable
|
||||
}
|
||||
|
||||
; CHECK: call foo
|
||||
; CHECK: jump ##__restore
|
||||
; The restore call will still be long because of the enable-save-restore-long
|
||||
; option being used.
|
||||
define i64 @test_shortcall(i32 %x, i32 %y) #3 {
|
||||
entry:
|
||||
%add = add nsw i32 %x, 5
|
||||
%call = tail call i64 @foo(i32 %add) #6
|
||||
%conv = sext i32 %y to i64
|
||||
%add1 = add nsw i64 %call, %conv
|
||||
ret i64 %add1
|
||||
}
|
||||
|
||||
; CHECK: jump foo
|
||||
define i64 @test_shorttailcall(i32 %x, i32 %y) #4 {
|
||||
entry:
|
||||
%add = add nsw i32 %x, 5
|
||||
%call = tail call i64 @foo(i32 %add) #6
|
||||
ret i64 %call
|
||||
}
|
||||
|
||||
; CHECK: call bar
|
||||
define i64 @test_shortnoret(i32 %x, i32 %y) #5 {
|
||||
entry:
|
||||
%add = add nsw i32 %x, 5
|
||||
%0 = tail call i64 @bar(i32 %add) #7
|
||||
unreachable
|
||||
}
|
||||
|
||||
declare i64 @foo(i32) #6
|
||||
declare i64 @bar(i32) #7
|
||||
|
||||
attributes #0 = { minsize nounwind "target-cpu"="hexagonv60" "target-features"="+long-calls" }
|
||||
attributes #1 = { nounwind "target-cpu"="hexagonv60" "target-features"="+long-calls" }
|
||||
attributes #2 = { noreturn nounwind "target-cpu"="hexagonv60" "target-features"="+long-calls" }
|
||||
|
||||
attributes #3 = { minsize nounwind "target-cpu"="hexagonv60" "target-features"="-long-calls" }
|
||||
attributes #4 = { nounwind "target-cpu"="hexagonv60" "target-features"="-long-calls" }
|
||||
attributes #5 = { noreturn nounwind "target-cpu"="hexagonv60" "target-features"="-long-calls" }
|
||||
|
||||
attributes #6 = { noreturn "target-cpu"="hexagonv60" }
|
||||
attributes #7 = { noreturn nounwind "target-cpu"="hexagonv60" }
|
Loading…
Reference in New Issue