mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 04:30:23 +00:00
PrologEpilogInserter: Rewrite API to determine callee save regsiters.
This changes TargetFrameLowering::processFunctionBeforeCalleeSavedScan(): - Rename the function to determineCalleeSaves() - Pass a bitset of callee saved registers by reference, thus avoiding the function-global PhysRegUsed bitset in MachineRegisterInfo. - Without PhysRegUsed the implementation is fine tuned to not save physcial registers which are only read but never modified. Related to rdar://21539507 Differential Revision: http://reviews.llvm.org/D10909 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@242165 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
93398438ff
commit
a36268215f
@ -647,6 +647,12 @@ public:
|
||||
/// deleted during LiveDebugVariables analysis.
|
||||
void markUsesInDebugValueAsUndef(unsigned Reg) const;
|
||||
|
||||
/// Return true if the specified register is modified in this function.
|
||||
/// This checks that no defining machine operands exist for the register or
|
||||
/// any of its aliases. Definitions found on functions marked noreturn are
|
||||
/// ignored.
|
||||
bool isPhysRegModified(unsigned PhysReg) const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Physical Register Use Info
|
||||
//===--------------------------------------------------------------------===//
|
||||
@ -655,9 +661,7 @@ public:
|
||||
/// function. Also check for clobbered aliases and registers clobbered by
|
||||
/// function calls with register mask operands.
|
||||
///
|
||||
/// This only works after register allocation. It is primarily used by
|
||||
/// PrologEpilogInserter to determine which callee-saved registers need
|
||||
/// spilling.
|
||||
/// This only works after register allocation.
|
||||
bool isPhysRegUsed(unsigned Reg) const {
|
||||
if (UsedPhysRegMask.test(Reg))
|
||||
return true;
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class BitVector;
|
||||
class CalleeSavedInfo;
|
||||
class MachineFunction;
|
||||
class RegScavenger;
|
||||
@ -226,13 +227,15 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// processFunctionBeforeCalleeSavedScan - This method is called immediately
|
||||
/// before PrologEpilogInserter scans the physical registers used to determine
|
||||
/// what callee saved registers should be spilled. This method is optional.
|
||||
virtual void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
RegScavenger *RS = nullptr) const {
|
||||
|
||||
}
|
||||
/// This method determines which of the registers reported by
|
||||
/// TargetRegisterInfo::getCalleeSavedRegs() should actually get saved.
|
||||
/// The default implementation checks populates the \p SavedRegs bitset with
|
||||
/// all registers which are modified in the function, targets may override
|
||||
/// this function to save additional registers.
|
||||
/// This method also sets up the register scavenger ensuring there is a free
|
||||
/// register or a frameindex available.
|
||||
virtual void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
|
||||
RegScavenger *RS = nullptr) const;
|
||||
|
||||
/// processFunctionBeforeFrameFinalized - This method is called immediately
|
||||
/// before the specified function's frame layout (MF.getFrameInfo()) is
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/Support/raw_os_ostream.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
@ -441,3 +442,49 @@ void MachineRegisterInfo::markUsesInDebugValueAsUndef(unsigned Reg) const {
|
||||
UseMI->getOperand(0).setReg(0U);
|
||||
}
|
||||
}
|
||||
|
||||
static const Function *getCalledFunction(const MachineInstr &MI) {
|
||||
for (const MachineOperand &MO : MI.operands()) {
|
||||
if (!MO.isGlobal())
|
||||
continue;
|
||||
const Function *Func = dyn_cast<Function>(MO.getGlobal());
|
||||
if (Func != nullptr)
|
||||
return Func;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool isNoReturnDef(const MachineOperand &MO) {
|
||||
// Anything which is not a noreturn function is a real def.
|
||||
const MachineInstr &MI = *MO.getParent();
|
||||
if (!MI.isCall())
|
||||
return false;
|
||||
const MachineBasicBlock &MBB = *MI.getParent();
|
||||
if (!MBB.succ_empty())
|
||||
return false;
|
||||
const MachineFunction &MF = *MBB.getParent();
|
||||
// We need to keep correct unwind information even if the function will
|
||||
// not return, since the runtime may need it.
|
||||
if (MF.getFunction()->hasFnAttribute(Attribute::UWTable))
|
||||
return false;
|
||||
const Function *Called = getCalledFunction(MI);
|
||||
if (Called == nullptr || !Called->hasFnAttribute(Attribute::NoReturn)
|
||||
|| !Called->hasFnAttribute(Attribute::NoUnwind))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MachineRegisterInfo::isPhysRegModified(unsigned PhysReg) const {
|
||||
if (UsedPhysRegMask.test(PhysReg))
|
||||
return true;
|
||||
const TargetRegisterInfo *TRI = getTargetRegisterInfo();
|
||||
for (MCRegAliasIterator AI(PhysReg, TRI, true); AI.isValid(); ++AI) {
|
||||
for (const MachineOperand &MO : make_range(def_begin(*AI), def_end())) {
|
||||
if (isNoReturnDef(MO))
|
||||
continue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -82,7 +82,8 @@ private:
|
||||
|
||||
void calculateSets(MachineFunction &Fn);
|
||||
void calculateCallsInformation(MachineFunction &Fn);
|
||||
void calculateCalleeSavedRegisters(MachineFunction &Fn);
|
||||
void assignCalleeSavedSpillSlots(MachineFunction &Fn,
|
||||
const BitVector &SavedRegs);
|
||||
void insertCSRSpillsAndRestores(MachineFunction &Fn);
|
||||
void calculateFrameObjectOffsets(MachineFunction &Fn);
|
||||
void replaceFrameIndices(MachineFunction &Fn);
|
||||
@ -183,13 +184,12 @@ bool PEI::runOnMachineFunction(MachineFunction &Fn) {
|
||||
// instructions.
|
||||
calculateCallsInformation(Fn);
|
||||
|
||||
// Allow the target machine to make some adjustments to the function
|
||||
// e.g. UsedPhysRegs before calculateCalleeSavedRegisters.
|
||||
TFI->processFunctionBeforeCalleeSavedScan(Fn, RS);
|
||||
// Determine which of the registers in the callee save list should be saved.
|
||||
BitVector SavedRegs;
|
||||
TFI->determineCalleeSaves(Fn, SavedRegs, RS);
|
||||
|
||||
// Scan the function for modified callee saved registers and insert spill code
|
||||
// for any callee saved registers that are modified.
|
||||
calculateCalleeSavedRegisters(Fn);
|
||||
// Insert spill code for any callee saved registers that are modified.
|
||||
assignCalleeSavedSpillSlots(Fn, SavedRegs);
|
||||
|
||||
// Determine placement of CSR spill/restore code:
|
||||
// place all spills in the entry block, all restores in return blocks.
|
||||
@ -295,39 +295,27 @@ void PEI::calculateCallsInformation(MachineFunction &Fn) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// calculateCalleeSavedRegisters - Scan the function for modified callee saved
|
||||
/// registers.
|
||||
void PEI::calculateCalleeSavedRegisters(MachineFunction &F) {
|
||||
const TargetRegisterInfo *RegInfo = F.getSubtarget().getRegisterInfo();
|
||||
const TargetFrameLowering *TFI = F.getSubtarget().getFrameLowering();
|
||||
MachineFrameInfo *MFI = F.getFrameInfo();
|
||||
|
||||
// Get the callee saved register list...
|
||||
const MCPhysReg *CSRegs = RegInfo->getCalleeSavedRegs(&F);
|
||||
|
||||
void PEI::assignCalleeSavedSpillSlots(MachineFunction &F,
|
||||
const BitVector &SavedRegs) {
|
||||
// These are used to keep track the callee-save area. Initialize them.
|
||||
MinCSFrameIndex = INT_MAX;
|
||||
MaxCSFrameIndex = 0;
|
||||
|
||||
// Early exit for targets which have no callee saved registers.
|
||||
if (!CSRegs || CSRegs[0] == 0)
|
||||
if (SavedRegs.empty())
|
||||
return;
|
||||
|
||||
// In Naked functions we aren't going to save any registers.
|
||||
if (F.getFunction()->hasFnAttribute(Attribute::Naked))
|
||||
return;
|
||||
const TargetRegisterInfo *RegInfo = F.getSubtarget().getRegisterInfo();
|
||||
const MCPhysReg *CSRegs = RegInfo->getCalleeSavedRegs(&F);
|
||||
|
||||
std::vector<CalleeSavedInfo> CSI;
|
||||
for (unsigned i = 0; CSRegs[i]; ++i) {
|
||||
unsigned Reg = CSRegs[i];
|
||||
// Functions which call __builtin_unwind_init get all their registers saved.
|
||||
if (F.getRegInfo().isPhysRegUsed(Reg) || F.getMMI().callsUnwindInit()) {
|
||||
// If the reg is modified, save it!
|
||||
if (SavedRegs.test(Reg))
|
||||
CSI.push_back(CalleeSavedInfo(Reg));
|
||||
}
|
||||
}
|
||||
|
||||
const TargetFrameLowering *TFI = F.getSubtarget().getFrameLowering();
|
||||
MachineFrameInfo *MFI = F.getFrameInfo();
|
||||
if (!TFI->assignCalleeSavedSpillSlots(F, RegInfo, CSI)) {
|
||||
// If target doesn't implement this, use generic code.
|
||||
|
||||
|
@ -11,9 +11,12 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/Target/TargetFrameLowering.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
#include "llvm/Target/TargetSubtargetInfo.h"
|
||||
@ -54,3 +57,30 @@ bool TargetFrameLowering::needsFrameIndexResolution(
|
||||
const MachineFunction &MF) const {
|
||||
return MF.getFrameInfo()->hasStackObjects();
|
||||
}
|
||||
|
||||
void TargetFrameLowering::determineCalleeSaves(MachineFunction &MF,
|
||||
BitVector &SavedRegs,
|
||||
RegScavenger *RS) const {
|
||||
// Get the callee saved register list...
|
||||
const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
|
||||
const MCPhysReg *CSRegs = TRI.getCalleeSavedRegs(&MF);
|
||||
|
||||
// Early exit if there are no callee saved registers.
|
||||
if (!CSRegs || CSRegs[0] == 0)
|
||||
return;
|
||||
|
||||
SavedRegs.resize(TRI.getNumRegs());
|
||||
|
||||
// In Naked functions we aren't going to save any registers.
|
||||
if (MF.getFunction()->hasFnAttribute(Attribute::Naked))
|
||||
return;
|
||||
|
||||
// Functions which call __builtin_unwind_init get all their registers saved.
|
||||
bool CallsUnwindInit = MF.getMMI().callsUnwindInit();
|
||||
const MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
for (unsigned i = 0; CSRegs[i]; ++i) {
|
||||
unsigned Reg = CSRegs[i];
|
||||
if (CallsUnwindInit || MRI.isPhysRegModified(Reg))
|
||||
SavedRegs.set(Reg);
|
||||
}
|
||||
}
|
||||
|
@ -877,28 +877,34 @@ bool AArch64FrameLowering::restoreCalleeSavedRegisters(
|
||||
return true;
|
||||
}
|
||||
|
||||
void AArch64FrameLowering::processFunctionBeforeCalleeSavedScan(
|
||||
MachineFunction &MF, RegScavenger *RS) const {
|
||||
void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
|
||||
BitVector &SavedRegs,
|
||||
RegScavenger *RS) const {
|
||||
// All calls are tail calls in GHC calling conv, and functions have no
|
||||
// prologue/epilogue.
|
||||
if (MF.getFunction()->getCallingConv() == CallingConv::GHC)
|
||||
return;
|
||||
|
||||
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
|
||||
const AArch64RegisterInfo *RegInfo = static_cast<const AArch64RegisterInfo *>(
|
||||
MF.getSubtarget().getRegisterInfo());
|
||||
AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
|
||||
MachineRegisterInfo *MRI = &MF.getRegInfo();
|
||||
SmallVector<unsigned, 4> UnspilledCSGPRs;
|
||||
SmallVector<unsigned, 4> UnspilledCSFPRs;
|
||||
|
||||
// The frame record needs to be created by saving the appropriate registers
|
||||
if (hasFP(MF)) {
|
||||
MRI->setPhysRegUsed(AArch64::FP);
|
||||
MRI->setPhysRegUsed(AArch64::LR);
|
||||
SavedRegs.set(AArch64::FP);
|
||||
SavedRegs.set(AArch64::LR);
|
||||
}
|
||||
|
||||
// Spill the BasePtr if it's used. Do this first thing so that the
|
||||
// getCalleeSavedRegs() below will get the right answer.
|
||||
if (RegInfo->hasBasePointer(MF))
|
||||
MRI->setPhysRegUsed(RegInfo->getBaseRegister());
|
||||
SavedRegs.set(RegInfo->getBaseRegister());
|
||||
|
||||
if (RegInfo->needsStackRealignment(MF) && !RegInfo->hasBasePointer(MF))
|
||||
MRI->setPhysRegUsed(AArch64::X9);
|
||||
SavedRegs.set(AArch64::X9);
|
||||
|
||||
// If any callee-saved registers are used, the frame cannot be eliminated.
|
||||
unsigned NumGPRSpilled = 0;
|
||||
@ -920,8 +926,8 @@ void AArch64FrameLowering::processFunctionBeforeCalleeSavedScan(
|
||||
AArch64::FPR64RegClass.contains(EvenReg)) &&
|
||||
"Register class mismatch!");
|
||||
|
||||
const bool OddRegUsed = MRI->isPhysRegUsed(OddReg);
|
||||
const bool EvenRegUsed = MRI->isPhysRegUsed(EvenReg);
|
||||
const bool OddRegUsed = SavedRegs.test(OddReg);
|
||||
const bool EvenRegUsed = SavedRegs.test(EvenReg);
|
||||
|
||||
// Early exit if none of the registers in the register pair is actually
|
||||
// used.
|
||||
@ -942,7 +948,7 @@ void AArch64FrameLowering::processFunctionBeforeCalleeSavedScan(
|
||||
if (OddRegUsed ^ EvenRegUsed) {
|
||||
// Find out which register is the additional spill.
|
||||
Reg = OddRegUsed ? EvenReg : OddReg;
|
||||
MRI->setPhysRegUsed(Reg);
|
||||
SavedRegs.set(Reg);
|
||||
}
|
||||
|
||||
DEBUG(dbgs() << ' ' << PrintReg(OddReg, RegInfo));
|
||||
@ -997,7 +1003,7 @@ void AArch64FrameLowering::processFunctionBeforeCalleeSavedScan(
|
||||
UnspilledCSGPRs.pop_back();
|
||||
DEBUG(dbgs() << "Spilling " << PrintReg(Reg, RegInfo)
|
||||
<< " to get a scratch register.\n");
|
||||
MRI->setPhysRegUsed(Reg);
|
||||
SavedRegs.set(Reg);
|
||||
ExtraCSSpill = true;
|
||||
++Count;
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ public:
|
||||
bool hasFP(const MachineFunction &MF) const override;
|
||||
bool hasReservedCallFrame(const MachineFunction &MF) const override;
|
||||
|
||||
void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
|
||||
RegScavenger *RS) const override;
|
||||
};
|
||||
|
||||
|
@ -800,7 +800,7 @@ void ARMFrameLowering::emitEpilogue(MachineFunction &MF,
|
||||
// This is bad, if an interrupt is taken after the mov, sp is in an
|
||||
// inconsistent state.
|
||||
// Use the first callee-saved register as a scratch register.
|
||||
assert(MF.getRegInfo().isPhysRegUsed(ARM::R4) &&
|
||||
assert(!MFI->getPristineRegs(MF).test(ARM::R4) &&
|
||||
"No scratch register to restore SP from FP!");
|
||||
emitT2RegPlusImmediate(MBB, MBBI, dl, ARM::R4, FramePtr, -NumBytes,
|
||||
ARMCC::AL, 0, TII);
|
||||
@ -1470,7 +1470,8 @@ static unsigned estimateRSStackSizeLimit(MachineFunction &MF,
|
||||
// callee-saved vector registers after realigning the stack. The vst1 and vld1
|
||||
// instructions take alignment hints that can improve performance.
|
||||
//
|
||||
static void checkNumAlignedDPRCS2Regs(MachineFunction &MF) {
|
||||
static void
|
||||
checkNumAlignedDPRCS2Regs(MachineFunction &MF, BitVector &SavedRegs) {
|
||||
MF.getInfo<ARMFunctionInfo>()->setNumAlignedDPRCS2Regs(0);
|
||||
if (!SpillAlignedNEONRegs)
|
||||
return;
|
||||
@ -1497,10 +1498,9 @@ static void checkNumAlignedDPRCS2Regs(MachineFunction &MF) {
|
||||
// callee-saved registers in order, but it can happen that there are holes in
|
||||
// the range. Registers above the hole will be spilled to the standard DPRCS
|
||||
// area.
|
||||
MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
unsigned NumSpills = 0;
|
||||
for (; NumSpills < 8; ++NumSpills)
|
||||
if (!MRI.isPhysRegUsed(ARM::D8 + NumSpills))
|
||||
if (!SavedRegs.test(ARM::D8 + NumSpills))
|
||||
break;
|
||||
|
||||
// Don't do this for just one d-register. It's not worth it.
|
||||
@ -1511,12 +1511,13 @@ static void checkNumAlignedDPRCS2Regs(MachineFunction &MF) {
|
||||
MF.getInfo<ARMFunctionInfo>()->setNumAlignedDPRCS2Regs(NumSpills);
|
||||
|
||||
// A scratch register is required for the vst1 / vld1 instructions.
|
||||
MF.getRegInfo().setPhysRegUsed(ARM::R4);
|
||||
SavedRegs.set(ARM::R4);
|
||||
}
|
||||
|
||||
void
|
||||
ARMFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
|
||||
BitVector &SavedRegs,
|
||||
RegScavenger *RS) const {
|
||||
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
|
||||
// This tells PEI to spill the FP as if it is any other callee-save register
|
||||
// to take advantage the eliminateFrameIndex machinery. This also ensures it
|
||||
// is spilled in the order specified by getCalleeSavedRegs() to make it easier
|
||||
@ -1543,12 +1544,12 @@ ARMFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
// FIXME: It will be better just to find spare register here.
|
||||
if (AFI->isThumb2Function() &&
|
||||
(MFI->hasVarSizedObjects() || RegInfo->needsStackRealignment(MF)))
|
||||
MRI.setPhysRegUsed(ARM::R4);
|
||||
SavedRegs.set(ARM::R4);
|
||||
|
||||
if (AFI->isThumb1OnlyFunction()) {
|
||||
// Spill LR if Thumb1 function uses variable length argument lists.
|
||||
if (AFI->getArgRegsSaveSize() > 0)
|
||||
MRI.setPhysRegUsed(ARM::LR);
|
||||
SavedRegs.set(ARM::LR);
|
||||
|
||||
// Spill R4 if Thumb1 epilogue has to restore SP from FP. We don't know
|
||||
// for sure what the stack size will be, but for this, an estimate is good
|
||||
@ -1558,23 +1559,23 @@ ARMFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
// FIXME: It will be better just to find spare register here.
|
||||
unsigned StackSize = MFI->estimateStackSize(MF);
|
||||
if (MFI->hasVarSizedObjects() || StackSize > 508)
|
||||
MRI.setPhysRegUsed(ARM::R4);
|
||||
SavedRegs.set(ARM::R4);
|
||||
}
|
||||
|
||||
// See if we can spill vector registers to aligned stack.
|
||||
checkNumAlignedDPRCS2Regs(MF);
|
||||
checkNumAlignedDPRCS2Regs(MF, SavedRegs);
|
||||
|
||||
// Spill the BasePtr if it's used.
|
||||
if (RegInfo->hasBasePointer(MF))
|
||||
MRI.setPhysRegUsed(RegInfo->getBaseRegister());
|
||||
SavedRegs.set(RegInfo->getBaseRegister());
|
||||
|
||||
// Don't spill FP if the frame can be eliminated. This is determined
|
||||
// by scanning the callee-save registers to see if any is used.
|
||||
// by scanning the callee-save registers to see if any is modified.
|
||||
const MCPhysReg *CSRegs = RegInfo->getCalleeSavedRegs(&MF);
|
||||
for (unsigned i = 0; CSRegs[i]; ++i) {
|
||||
unsigned Reg = CSRegs[i];
|
||||
bool Spilled = false;
|
||||
if (MRI.isPhysRegUsed(Reg)) {
|
||||
if (SavedRegs.test(Reg)) {
|
||||
Spilled = true;
|
||||
CanEliminateFrame = false;
|
||||
}
|
||||
@ -1668,7 +1669,7 @@ ARMFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
// If LR is not spilled, but at least one of R4, R5, R6, and R7 is spilled.
|
||||
// Spill LR as well so we can fold BX_RET to the registers restore (LDM).
|
||||
if (!LRSpilled && CS1Spilled) {
|
||||
MRI.setPhysRegUsed(ARM::LR);
|
||||
SavedRegs.set(ARM::LR);
|
||||
NumGPRSpills++;
|
||||
SmallVectorImpl<unsigned>::iterator LRPos;
|
||||
LRPos = std::find(UnspilledCS1GPRs.begin(), UnspilledCS1GPRs.end(),
|
||||
@ -1681,7 +1682,7 @@ ARMFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
}
|
||||
|
||||
if (hasFP(MF)) {
|
||||
MRI.setPhysRegUsed(FramePtr);
|
||||
SavedRegs.set(FramePtr);
|
||||
auto FPPos = std::find(UnspilledCS1GPRs.begin(), UnspilledCS1GPRs.end(),
|
||||
FramePtr);
|
||||
if (FPPos != UnspilledCS1GPRs.end())
|
||||
@ -1700,7 +1701,7 @@ ARMFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
// Don't spill high register if the function is thumb
|
||||
if (!AFI->isThumbFunction() ||
|
||||
isARMLowRegister(Reg) || Reg == ARM::LR) {
|
||||
MRI.setPhysRegUsed(Reg);
|
||||
SavedRegs.set(Reg);
|
||||
if (!MRI.isReserved(Reg))
|
||||
ExtraCSSpill = true;
|
||||
break;
|
||||
@ -1708,7 +1709,7 @@ ARMFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
}
|
||||
} else if (!UnspilledCS2GPRs.empty() && !AFI->isThumb1OnlyFunction()) {
|
||||
unsigned Reg = UnspilledCS2GPRs.front();
|
||||
MRI.setPhysRegUsed(Reg);
|
||||
SavedRegs.set(Reg);
|
||||
if (!MRI.isReserved(Reg))
|
||||
ExtraCSSpill = true;
|
||||
}
|
||||
@ -1747,7 +1748,7 @@ ARMFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
}
|
||||
if (Extras.size() && NumExtras == 0) {
|
||||
for (unsigned i = 0, e = Extras.size(); i != e; ++i) {
|
||||
MRI.setPhysRegUsed(Extras[i]);
|
||||
SavedRegs.set(Extras[i]);
|
||||
}
|
||||
} else if (!AFI->isThumb1OnlyFunction()) {
|
||||
// note: Thumb1 functions spill to R12, not the stack. Reserve a slot
|
||||
@ -1761,7 +1762,7 @@ ARMFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
}
|
||||
|
||||
if (ForceLRSpill) {
|
||||
MRI.setPhysRegUsed(ARM::LR);
|
||||
SavedRegs.set(ARM::LR);
|
||||
AFI->setLRIsSpilledForFarJump(true);
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ public:
|
||||
unsigned &FrameReg, int SPAdj) const;
|
||||
int getFrameIndexOffset(const MachineFunction &MF, int FI) const override;
|
||||
|
||||
void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
|
||||
RegScavenger *RS) const override;
|
||||
|
||||
void adjustForSegmentedStacks(MachineFunction &MF,
|
||||
|
@ -365,7 +365,7 @@ void Thumb1FrameLowering::emitEpilogue(MachineFunction &MF,
|
||||
// frame pointer stack slot, the target is ELF and the function has FP, or
|
||||
// the target uses var sized objects.
|
||||
if (NumBytes) {
|
||||
assert(MF.getRegInfo().isPhysRegUsed(ARM::R4) &&
|
||||
assert(!MFI->getPristineRegs(MF).test(ARM::R4) &&
|
||||
"No scratch register to restore SP from FP!");
|
||||
emitThumbRegPlusImmediate(MBB, MBBI, dl, ARM::R4, FramePtr, -NumBytes,
|
||||
TII, *RegInfo);
|
||||
|
@ -29,12 +29,12 @@ void BPFFrameLowering::emitPrologue(MachineFunction &MF,
|
||||
void BPFFrameLowering::emitEpilogue(MachineFunction &MF,
|
||||
MachineBasicBlock &MBB) const {}
|
||||
|
||||
void BPFFrameLowering::processFunctionBeforeCalleeSavedScan(
|
||||
MachineFunction &MF, RegScavenger *RS) const {
|
||||
MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
|
||||
MRI.setPhysRegUnused(BPF::R6);
|
||||
MRI.setPhysRegUnused(BPF::R7);
|
||||
MRI.setPhysRegUnused(BPF::R8);
|
||||
MRI.setPhysRegUnused(BPF::R9);
|
||||
void BPFFrameLowering::determineCalleeSaves(MachineFunction &MF,
|
||||
BitVector &SavedRegs,
|
||||
RegScavenger *RS) const {
|
||||
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
|
||||
SavedRegs.reset(BPF::R6);
|
||||
SavedRegs.reset(BPF::R7);
|
||||
SavedRegs.reset(BPF::R8);
|
||||
SavedRegs.reset(BPF::R9);
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ public:
|
||||
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
|
||||
|
||||
bool hasFP(const MachineFunction &MF) const override;
|
||||
void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
|
||||
RegScavenger *RS) const override;
|
||||
|
||||
void
|
||||
|
@ -959,8 +959,11 @@ bool HexagonFrameLowering::replacePredRegPseudoSpillCode(MachineFunction &MF)
|
||||
}
|
||||
|
||||
|
||||
void HexagonFrameLowering::processFunctionBeforeCalleeSavedScan(
|
||||
MachineFunction &MF, RegScavenger* RS) const {
|
||||
void HexagonFrameLowering::determineCalleeSaves(MachineFunction &MF,
|
||||
BitVector &SavedRegs,
|
||||
RegScavenger *RS) const {
|
||||
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
|
||||
|
||||
auto &HST = static_cast<const HexagonSubtarget&>(MF.getSubtarget());
|
||||
auto &HRI = *HST.getRegisterInfo();
|
||||
|
||||
@ -969,11 +972,9 @@ void HexagonFrameLowering::processFunctionBeforeCalleeSavedScan(
|
||||
// If we have a function containing __builtin_eh_return we want to spill and
|
||||
// restore all callee saved registers. Pretend that they are used.
|
||||
if (HasEHReturn) {
|
||||
MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
for (const MCPhysReg *CSRegs = HRI.getCalleeSavedRegs(&MF); *CSRegs;
|
||||
++CSRegs)
|
||||
if (!MRI.isPhysRegUsed(*CSRegs))
|
||||
MRI.setPhysRegUsed(*CSRegs);
|
||||
SavedRegs.set(*CSRegs);
|
||||
}
|
||||
|
||||
const TargetRegisterClass &RC = Hexagon::IntRegsRegClass;
|
||||
|
@ -45,7 +45,7 @@ public:
|
||||
MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const override;
|
||||
void processFunctionBeforeFrameFinalized(MachineFunction &MF,
|
||||
RegScavenger *RS = nullptr) const override;
|
||||
void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
|
||||
RegScavenger *RS) const override;
|
||||
|
||||
bool targetHandlesStackFrameRounding() const override {
|
||||
|
@ -152,18 +152,19 @@ Mips16FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
|
||||
return isInt<15>(MFI->getMaxCallFrameSize()) && !MFI->hasVarSizedObjects();
|
||||
}
|
||||
|
||||
void Mips16FrameLowering::
|
||||
processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
void Mips16FrameLowering::determineCalleeSaves(MachineFunction &MF,
|
||||
BitVector &SavedRegs,
|
||||
RegScavenger *RS) const {
|
||||
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
|
||||
const Mips16InstrInfo &TII =
|
||||
*static_cast<const Mips16InstrInfo *>(STI.getInstrInfo());
|
||||
const MipsRegisterInfo &RI = TII.getRegisterInfo();
|
||||
const BitVector Reserved = RI.getReservedRegs(MF);
|
||||
bool SaveS2 = Reserved[Mips::S2];
|
||||
if (SaveS2)
|
||||
MF.getRegInfo().setPhysRegUsed(Mips::S2);
|
||||
SavedRegs.set(Mips::S2);
|
||||
if (hasFP(MF))
|
||||
MF.getRegInfo().setPhysRegUsed(Mips::S0);
|
||||
SavedRegs.set(Mips::S0);
|
||||
}
|
||||
|
||||
const MipsFrameLowering *
|
||||
|
@ -38,7 +38,7 @@ public:
|
||||
|
||||
bool hasReservedCallFrame(const MachineFunction &MF) const override;
|
||||
|
||||
void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
|
||||
RegScavenger *RS) const override;
|
||||
};
|
||||
|
||||
|
@ -621,10 +621,17 @@ MipsSEFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
|
||||
!MFI->hasVarSizedObjects();
|
||||
}
|
||||
|
||||
void MipsSEFrameLowering::
|
||||
processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
/// Mark \p Reg and all registers aliasing it in the bitset.
|
||||
void setAliasRegs(MachineFunction &MF, BitVector &SavedRegs, unsigned Reg) {
|
||||
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
|
||||
for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI)
|
||||
SavedRegs.set(*AI);
|
||||
}
|
||||
|
||||
void MipsSEFrameLowering::determineCalleeSaves(MachineFunction &MF,
|
||||
BitVector &SavedRegs,
|
||||
RegScavenger *RS) const {
|
||||
MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
|
||||
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
|
||||
MipsABIInfo ABI = STI.getABI();
|
||||
unsigned FP = ABI.GetFramePtr();
|
||||
@ -632,10 +639,10 @@ processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
|
||||
// Mark $fp as used if function has dedicated frame pointer.
|
||||
if (hasFP(MF))
|
||||
MRI.setPhysRegUsed(FP);
|
||||
setAliasRegs(MF, SavedRegs, FP);
|
||||
// Mark $s7 as used if function has dedicated base pointer.
|
||||
if (hasBP(MF))
|
||||
MRI.setPhysRegUsed(BP);
|
||||
setAliasRegs(MF, SavedRegs, BP);
|
||||
|
||||
// Create spill slots for eh data registers if function calls eh_return.
|
||||
if (MipsFI->callsEhReturn())
|
||||
|
@ -34,7 +34,7 @@ public:
|
||||
|
||||
bool hasReservedCallFrame(const MachineFunction &MF) const override;
|
||||
|
||||
void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
|
||||
RegScavenger *RS) const override;
|
||||
unsigned ehDataReg(unsigned I) const;
|
||||
};
|
||||
|
@ -1158,9 +1158,11 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PPCFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
RegScavenger *) const {
|
||||
void PPCFrameLowering::determineCalleeSaves(MachineFunction &MF,
|
||||
BitVector &SavedRegs,
|
||||
RegScavenger *RS) const {
|
||||
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
|
||||
|
||||
const PPCRegisterInfo *RegInfo =
|
||||
static_cast<const PPCRegisterInfo *>(Subtarget.getRegisterInfo());
|
||||
|
||||
@ -1168,8 +1170,7 @@ PPCFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
PPCFunctionInfo *FI = MF.getInfo<PPCFunctionInfo>();
|
||||
unsigned LR = RegInfo->getRARegister();
|
||||
FI->setMustSaveLR(MustSaveLR(MF, LR));
|
||||
MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
MRI.setPhysRegUnused(LR);
|
||||
SavedRegs.reset(LR);
|
||||
|
||||
// Save R31 if necessary
|
||||
int FPSI = FI->getFramePointerSaveIndex();
|
||||
@ -1214,9 +1215,9 @@ PPCFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
// For 32-bit SVR4, allocate the nonvolatile CR spill slot iff the
|
||||
// function uses CR 2, 3, or 4.
|
||||
if (!isPPC64 && !isDarwinABI &&
|
||||
(MRI.isPhysRegUsed(PPC::CR2) ||
|
||||
MRI.isPhysRegUsed(PPC::CR3) ||
|
||||
MRI.isPhysRegUsed(PPC::CR4))) {
|
||||
(SavedRegs.test(PPC::CR2) ||
|
||||
SavedRegs.test(PPC::CR3) ||
|
||||
SavedRegs.test(PPC::CR4))) {
|
||||
int FrameIdx = MFI->CreateFixedObject((uint64_t)4, (int64_t)-4, true);
|
||||
FI->setCRSpillFrameIndex(FrameIdx);
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ public:
|
||||
bool needsFP(const MachineFunction &MF) const;
|
||||
void replaceFPWithRealFP(MachineFunction &MF) const;
|
||||
|
||||
void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
|
||||
RegScavenger *RS = nullptr) const override;
|
||||
void processFunctionBeforeFrameFinalized(MachineFunction &MF,
|
||||
RegScavenger *RS = nullptr) const override;
|
||||
|
@ -247,9 +247,10 @@ void SparcFrameLowering::remapRegsForLeafProc(MachineFunction &MF) const {
|
||||
#endif
|
||||
}
|
||||
|
||||
void SparcFrameLowering::processFunctionBeforeCalleeSavedScan
|
||||
(MachineFunction &MF, RegScavenger *RS) const {
|
||||
|
||||
void SparcFrameLowering::determineCalleeSaves(MachineFunction &MF,
|
||||
BitVector &SavedRegs,
|
||||
RegScavenger *RS) const {
|
||||
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
|
||||
if (!DisableLeafProc && isLeafProc(MF)) {
|
||||
SparcMachineFunctionInfo *MFI = MF.getInfo<SparcMachineFunctionInfo>();
|
||||
MFI->setLeafProc(true);
|
||||
|
@ -36,7 +36,7 @@ public:
|
||||
|
||||
bool hasReservedCallFrame(const MachineFunction &MF) const override;
|
||||
bool hasFP(const MachineFunction &MF) const override;
|
||||
void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
|
||||
RegScavenger *RS = nullptr) const override;
|
||||
|
||||
private:
|
||||
|
@ -61,11 +61,12 @@ SystemZFrameLowering::getCalleeSavedSpillSlots(unsigned &NumEntries) const {
|
||||
return SpillOffsetTable;
|
||||
}
|
||||
|
||||
void SystemZFrameLowering::
|
||||
processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
void SystemZFrameLowering::determineCalleeSaves(MachineFunction &MF,
|
||||
BitVector &SavedRegs,
|
||||
RegScavenger *RS) const {
|
||||
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
|
||||
|
||||
MachineFrameInfo *MFFrame = MF.getFrameInfo();
|
||||
MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
|
||||
bool HasFP = hasFP(MF);
|
||||
SystemZMachineFunctionInfo *MFI = MF.getInfo<SystemZMachineFunctionInfo>();
|
||||
@ -77,17 +78,17 @@ processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
// argument register R6D.
|
||||
if (IsVarArg)
|
||||
for (unsigned I = MFI->getVarArgsFirstGPR(); I < SystemZ::NumArgGPRs; ++I)
|
||||
MRI.setPhysRegUsed(SystemZ::ArgGPRs[I]);
|
||||
SavedRegs.set(SystemZ::ArgGPRs[I]);
|
||||
|
||||
// If the function requires a frame pointer, record that the hard
|
||||
// frame pointer will be clobbered.
|
||||
if (HasFP)
|
||||
MRI.setPhysRegUsed(SystemZ::R11D);
|
||||
SavedRegs.set(SystemZ::R11D);
|
||||
|
||||
// If the function calls other functions, record that the return
|
||||
// address register will be clobbered.
|
||||
if (MFFrame->hasCalls())
|
||||
MRI.setPhysRegUsed(SystemZ::R14D);
|
||||
SavedRegs.set(SystemZ::R14D);
|
||||
|
||||
// If we are saving GPRs other than the stack pointer, we might as well
|
||||
// save and restore the stack pointer at the same time, via STMG and LMG.
|
||||
@ -96,8 +97,8 @@ processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
const MCPhysReg *CSRegs = TRI->getCalleeSavedRegs(&MF);
|
||||
for (unsigned I = 0; CSRegs[I]; ++I) {
|
||||
unsigned Reg = CSRegs[I];
|
||||
if (SystemZ::GR64BitRegClass.contains(Reg) && MRI.isPhysRegUsed(Reg)) {
|
||||
MRI.setPhysRegUsed(SystemZ::R15D);
|
||||
if (SystemZ::GR64BitRegClass.contains(Reg) && SavedRegs.test(Reg)) {
|
||||
SavedRegs.set(SystemZ::R15D);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ public:
|
||||
bool isFPCloseToIncomingSP() const override { return false; }
|
||||
const SpillSlot *getCalleeSavedSpillSlots(unsigned &NumEntries) const
|
||||
override;
|
||||
void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
|
||||
RegScavenger *RS) const override;
|
||||
bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MBBI,
|
||||
|
@ -1425,9 +1425,11 @@ bool X86FrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
X86FrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
void X86FrameLowering::determineCalleeSaves(MachineFunction &MF,
|
||||
BitVector &SavedRegs,
|
||||
RegScavenger *RS) const {
|
||||
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
|
||||
|
||||
MachineFrameInfo *MFI = MF.getFrameInfo();
|
||||
|
||||
X86MachineFunctionInfo *X86FI = MF.getInfo<X86MachineFunctionInfo>();
|
||||
@ -1449,7 +1451,7 @@ X86FrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
|
||||
// Spill the BasePtr if it's used.
|
||||
if (TRI->hasBasePointer(MF))
|
||||
MF.getRegInfo().setPhysRegUsed(TRI->getBaseRegister());
|
||||
SavedRegs.set(TRI->getBaseRegister());
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -68,7 +68,7 @@ public:
|
||||
void adjustForHiPEPrologue(MachineFunction &MF,
|
||||
MachineBasicBlock &PrologueMBB) const override;
|
||||
|
||||
void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
|
||||
RegScavenger *RS = nullptr) const override;
|
||||
|
||||
bool
|
||||
|
@ -525,12 +525,15 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
|
||||
MBB.erase(I);
|
||||
}
|
||||
|
||||
void XCoreFrameLowering::
|
||||
processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
void XCoreFrameLowering::determineCalleeSaves(MachineFunction &MF,
|
||||
BitVector &SavedRegs,
|
||||
RegScavenger *RS) const {
|
||||
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
|
||||
|
||||
XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>();
|
||||
|
||||
bool LRUsed = MF.getRegInfo().isPhysRegUsed(XCore::LR);
|
||||
const MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
bool LRUsed = MRI.isPhysRegModified(XCore::LR);
|
||||
|
||||
if (!LRUsed && !MF.getFunction()->isVarArg() &&
|
||||
MF.getFrameInfo()->estimateStackSize(MF))
|
||||
@ -550,7 +553,7 @@ processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
if (LRUsed) {
|
||||
// We will handle the LR in the prologue/epilogue
|
||||
// and allocate space on the stack ourselves.
|
||||
MF.getRegInfo().setPhysRegUnused(XCore::LR);
|
||||
SavedRegs.reset(XCore::LR);
|
||||
XFI->createLRSpillSlot(MF);
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ namespace llvm {
|
||||
|
||||
bool hasFP(const MachineFunction &MF) const override;
|
||||
|
||||
void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
|
||||
RegScavenger *RS = nullptr) const override;
|
||||
|
||||
void processFunctionBeforeFrameFinalized(MachineFunction &MF,
|
||||
|
@ -8,7 +8,6 @@
|
||||
define i8* @rt0(i32 %x) nounwind readnone {
|
||||
entry:
|
||||
; CHECK-LABEL: rt0:
|
||||
; CHECK: {r7, lr}
|
||||
; CHECK: mov r0, lr
|
||||
%0 = tail call i8* @llvm.returnaddress(i32 0)
|
||||
ret i8* %0
|
||||
@ -17,10 +16,9 @@ entry:
|
||||
define i8* @rt2() nounwind readnone {
|
||||
entry:
|
||||
; CHECK-LABEL: rt2:
|
||||
; CHECK: {r7, lr}
|
||||
; CHECK: ldr r[[R0:[0-9]+]], [r7]
|
||||
; CHECK: ldr r0, [r0]
|
||||
; CHECK: ldr r0, [r0, #4]
|
||||
; CHECK: ldr r0, [r[[R0]]]
|
||||
; CHECK: ldr r0, [r[[R0]], #4]
|
||||
%0 = tail call i8* @llvm.returnaddress(i32 2)
|
||||
ret i8* %0
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user