Allow {e,r}bp as the target of {read,write}_register.

This patch allows the read_register and write_register intrinsics to
read/write the RBP/EBP registers on X86 iff the targeted register is
the frame pointer for the containing function.

Differential Revision: http://reviews.llvm.org/D10977

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@241827 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Pat Gavlin 2015-07-09 17:40:29 +00:00
parent dc219dddde
commit db5a82b861
14 changed files with 90 additions and 18 deletions

View File

@ -2487,7 +2487,8 @@ public:
/// Return the register ID of the name passed in. Used by named register
/// global variables extension. There is no target-independent behaviour
/// so the default action is to bail.
virtual unsigned getRegisterByName(const char* RegName, EVT VT) const {
virtual unsigned getRegisterByName(const char* RegName, EVT VT,
SelectionDAG &DAG) const {
report_fatal_error("Named registers not implemented for this target");
}

View File

@ -1932,7 +1932,8 @@ SDNode
MDNodeSDNode *MD = dyn_cast<MDNodeSDNode>(Op->getOperand(1));
const MDString *RegStr = dyn_cast<MDString>(MD->getMD()->getOperand(0));
unsigned Reg =
TLI->getRegisterByName(RegStr->getString().data(), Op->getValueType(0));
TLI->getRegisterByName(RegStr->getString().data(), Op->getValueType(0),
*CurDAG);
SDValue New = CurDAG->getCopyFromReg(
Op->getOperand(0), dl, Reg, Op->getValueType(0));
New->setNodeId(-1);
@ -1945,7 +1946,8 @@ SDNode
MDNodeSDNode *MD = dyn_cast<MDNodeSDNode>(Op->getOperand(1));
const MDString *RegStr = dyn_cast<MDString>(MD->getMD()->getOperand(0));
unsigned Reg = TLI->getRegisterByName(RegStr->getString().data(),
Op->getOperand(2).getValueType());
Op->getOperand(2).getValueType(),
*CurDAG);
SDValue New = CurDAG->getCopyToReg(
Op->getOperand(0), dl, Reg, Op->getOperand(2));
New->setNodeId(-1);

View File

@ -4065,8 +4065,8 @@ SDValue AArch64TargetLowering::LowerFRAMEADDR(SDValue Op,
// FIXME? Maybe this could be a TableGen attribute on some registers and
// this table could be generated automatically from RegInfo.
unsigned AArch64TargetLowering::getRegisterByName(const char* RegName,
EVT VT) const {
unsigned AArch64TargetLowering::getRegisterByName(const char* RegName, EVT VT,
SelectionDAG &DAG) const {
unsigned Reg = StringSwitch<unsigned>(RegName)
.Case("sp", AArch64::SP)
.Default(0);

View File

@ -473,7 +473,8 @@ private:
bool combineRepeatedFPDivisors(unsigned NumUsers) const override;
ConstraintType getConstraintType(StringRef Constraint) const override;
unsigned getRegisterByName(const char* RegName, EVT VT) const override;
unsigned getRegisterByName(const char* RegName, EVT VT,
SelectionDAG &DAG) const override;
/// Examine constraint string and operand type and determine a weight value.
/// The operand object must already have been set up with the operand type.

View File

@ -4101,8 +4101,8 @@ SDValue ARMTargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const {
// FIXME? Maybe this could be a TableGen attribute on some registers and
// this table could be generated automatically from RegInfo.
unsigned ARMTargetLowering::getRegisterByName(const char* RegName,
EVT VT) const {
unsigned ARMTargetLowering::getRegisterByName(const char* RegName, EVT VT,
SelectionDAG &DAG) const {
unsigned Reg = StringSwitch<unsigned>(RegName)
.Case("sp", ARM::SP)
.Default(0);

View File

@ -532,7 +532,8 @@ namespace llvm {
SDValue LowerFP_TO_INT(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerINT_TO_FP(SDValue Op, SelectionDAG &DAG) const;
unsigned getRegisterByName(const char* RegName, EVT VT) const override;
unsigned getRegisterByName(const char* RegName, EVT VT,
SelectionDAG &DAG) const override;
/// isFMAFasterThanFMulAndFAdd - Return true if an FMA operation is faster
/// than a pair of fmul and fadd instructions. fmuladd intrinsics will be

View File

@ -3927,8 +3927,8 @@ MipsTargetLowering::emitPseudoSELECT(MachineInstr *MI, MachineBasicBlock *BB,
// FIXME? Maybe this could be a TableGen attribute on some registers and
// this table could be generated automatically from RegInfo.
unsigned MipsTargetLowering::getRegisterByName(const char* RegName,
EVT VT) const {
unsigned MipsTargetLowering::getRegisterByName(const char* RegName, EVT VT,
SelectionDAG &DAG) const {
// Named registers is expected to be fairly rare. For now, just support $28
// since the linux kernel uses it.
if (Subtarget.isGP64bit()) {

View File

@ -266,7 +266,8 @@ namespace llvm {
void HandleByVal(CCState *, unsigned &, unsigned) const override;
unsigned getRegisterByName(const char* RegName, EVT VT) const override;
unsigned getRegisterByName(const char* RegName, EVT VT,
SelectionDAG &DAG) const override;
protected:
SDValue getGlobalReg(SelectionDAG &DAG, EVT Ty) const;

View File

@ -11031,8 +11031,8 @@ SDValue PPCTargetLowering::LowerFRAMEADDR(SDValue Op,
// FIXME? Maybe this could be a TableGen attribute on some registers and
// this table could be generated automatically from RegInfo.
unsigned PPCTargetLowering::getRegisterByName(const char* RegName,
EVT VT) const {
unsigned PPCTargetLowering::getRegisterByName(const char* RegName, EVT VT,
SelectionDAG &DAG) const {
bool isPPC64 = Subtarget.isPPC64();
bool isDarwinABI = Subtarget.isDarwinABI();

View File

@ -490,7 +490,8 @@ namespace llvm {
SDValue BuildSDIVPow2(SDNode *N, const APInt &Divisor, SelectionDAG &DAG,
std::vector<SDNode *> *Created) const override;
unsigned getRegisterByName(const char* RegName, EVT VT) const override;
unsigned getRegisterByName(const char* RegName, EVT VT,
SelectionDAG &DAG) const override;
void computeKnownBitsForTargetNode(const SDValue Op,
APInt &KnownZero,

View File

@ -16262,14 +16262,36 @@ SDValue X86TargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const {
// FIXME? Maybe this could be a TableGen attribute on some registers and
// this table could be generated automatically from RegInfo.
unsigned X86TargetLowering::getRegisterByName(const char* RegName,
EVT VT) const {
unsigned X86TargetLowering::getRegisterByName(const char* RegName, EVT VT,
SelectionDAG &DAG) const {
const TargetFrameLowering &TFI = *Subtarget->getFrameLowering();
const MachineFunction &MF = DAG.getMachineFunction();
unsigned Reg = StringSwitch<unsigned>(RegName)
.Case("esp", X86::ESP)
.Case("rsp", X86::RSP)
.Case("ebp", X86::EBP)
.Case("rbp", X86::RBP)
.Default(0);
if (Reg == X86::EBP || Reg == X86::RBP) {
if (!TFI.hasFP(MF))
report_fatal_error("register " + StringRef(RegName) +
" is allocatable: function has no frame pointer");
#ifndef NDEBUG
else {
const X86RegisterInfo *RegInfo = Subtarget->getRegisterInfo();
unsigned FrameReg =
RegInfo->getPtrSizedFrameRegister(DAG.getMachineFunction());
assert((FrameReg == X86::EBP || FrameReg == X86::RBP) &&
"Invalid Frame Register!");
}
#endif
}
if (Reg)
return Reg;
report_fatal_error("Invalid register name global variable");
}

View File

@ -873,7 +873,8 @@ namespace llvm {
return nullptr; // nothing to do, move along.
}
unsigned getRegisterByName(const char* RegName, EVT VT) const override;
unsigned getRegisterByName(const char* RegName, EVT VT,
SelectionDAG &DAG) const override;
/// This method returns a target specific FastISel object,
/// or null if the target does not support "fast" ISel.

View File

@ -0,0 +1,30 @@
; RUN: llc < %s -mtriple=x86_64-apple-darwin | FileCheck %s
; RUN: llc < %s -mtriple=x86_64-linux-gnueabi | FileCheck %s
; RUN: opt < %s -O3 -S -mtriple=x86_64-linux-gnueabi | FileCheck %s --check-prefix=OPT
define i64 @get_frame() #0 {
entry:
; CHECK-LABEL: get_frame:
; CHECK: movq %rbp, %rax
%sp = call i64 @llvm.read_register.i64(metadata !0)
; OPT: @llvm.read_register.i64
ret i64 %sp
}
define void @set_frame(i64 %val) #0 {
entry:
; CHECK-LABEL: set_frame:
; CHECK: movq %rdi, %rbp
call void @llvm.write_register.i64(metadata !0, i64 %val)
; OPT: @llvm.write_register.i64
ret void
}
declare i64 @llvm.read_register.i64(metadata) nounwind
declare void @llvm.write_register.i64(metadata, i64) nounwind
; register unsigned long current_stack_pointer asm("rbp");
; CHECK-NOT: .asciz "rbp"
!0 = !{!"rbp\00"}
attributes #0 = { nounwind "no-frame-pointer-elim"="true" }

View File

@ -0,0 +1,12 @@
; RUN: not llc < %s -mtriple=x86_64-linux-gnueabi 2>&1 | FileCheck %s
define i32 @get_frame() nounwind {
entry:
; CHECK: register ebp is allocatable: function has no frame pointer
%fp = call i32 @llvm.read_register.i32(metadata !0)
ret i32 %fp
}
declare i32 @llvm.read_register.i32(metadata) nounwind
!0 = !{!"ebp\00"}