diff --git a/lib/Target/X86/X86FastISel.cpp b/lib/Target/X86/X86FastISel.cpp index c77e95c0ae9..2b6b378059b 100644 --- a/lib/Target/X86/X86FastISel.cpp +++ b/lib/Target/X86/X86FastISel.cpp @@ -1653,6 +1653,58 @@ bool X86FastISel::X86VisitIntrinsicCall(const IntrinsicInst &I) { // FIXME: Handle more intrinsics. switch (I.getIntrinsicID()) { default: return false; + case Intrinsic::frameaddress: { + Type *RetTy = I.getCalledFunction()->getReturnType(); + + MVT VT; + if (!isTypeLegal(RetTy, VT)) + return false; + + unsigned Opc; + const TargetRegisterClass *RC = nullptr; + + switch (VT.SimpleTy) { + default: llvm_unreachable("Invalid result type for frameaddress."); + case MVT::i32: Opc = X86::MOV32rm; RC = &X86::GR32RegClass; break; + case MVT::i64: Opc = X86::MOV64rm; RC = &X86::GR64RegClass; break; + } + + // This needs to be set before we call getFrameRegister, otherwise we get + // the wrong frame register. + MachineFrameInfo *MFI = FuncInfo.MF->getFrameInfo(); + MFI->setFrameAddressIsTaken(true); + + const X86RegisterInfo *RegInfo = + static_cast(TM.getRegisterInfo()); + unsigned FrameReg = RegInfo->getFrameRegister(*(FuncInfo.MF)); + assert(((FrameReg == X86::RBP && VT == MVT::i64) || + (FrameReg == X86::EBP && VT == MVT::i32)) && + "Invalid Frame Register!"); + + // Always make a copy of the frame register to to a vreg first, so that we + // never directly reference the frame register (the TwoAddressInstruction- + // Pass doesn't like that). + unsigned SrcReg = createResultReg(RC); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + TII.get(TargetOpcode::COPY), SrcReg).addReg(FrameReg); + + // Now recursively load from the frame address. + // movq (%rbp), %rax + // movq (%rax), %rax + // movq (%rax), %rax + // ... + unsigned DestReg; + unsigned Depth = cast(I.getOperand(0))->getZExtValue(); + while (Depth--) { + DestReg = createResultReg(RC); + addDirectMem(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + TII.get(Opc), DestReg), SrcReg); + SrcReg = DestReg; + } + + UpdateValueMap(&I, SrcReg); + return true; + } case Intrinsic::memcpy: { const MemCpyInst &MCI = cast(I); // Don't handle volatile or variable length memcpys. diff --git a/test/CodeGen/X86/frameaddr.ll b/test/CodeGen/X86/frameaddr.ll new file mode 100644 index 00000000000..999f3a584db --- /dev/null +++ b/test/CodeGen/X86/frameaddr.ll @@ -0,0 +1,27 @@ +; RUN: llc < %s -march=x86 | FileCheck %s --check-prefix=CHECK-32 +; RUN: llc < %s -march=x86 -fast-isel -fast-isel-abort | FileCheck %s --check-prefix=CHECK-32 +; RUN: llc < %s -march=x86-64 | FileCheck %s --check-prefix=CHECK-64 +; RUN: llc < %s -march=x86-64 -fast-isel -fast-isel-abort | FileCheck %s --check-prefix=CHECK-64 + +define i8* @test1() nounwind { +entry: +; CHECK-32: movl %esp, %ebp +; CHECK-32-NEXT: movl %ebp, %eax +; CHECK-64: movq %rsp, %rbp +; CHECK-64-NEXT: movq %rbp, %rax + %0 = tail call i8* @llvm.frameaddress(i32 0) + ret i8* %0 +} + +define i8* @test2() nounwind { +entry: +; CHECK-32: movl %esp, %ebp +; CHECK-32-NEXT: movl (%ebp), %eax +; CHECK-32-NEXT: movl (%eax), %eax +; CHECK-64: movq %rsp, %rbp +; CHECK-64-NEXT: movq (%rbp), %rax +; CHECK-64-NEXT: movq (%rax), %rax + %0 = tail call i8* @llvm.frameaddress(i32 2) + ret i8* %0 +} +declare i8* @llvm.frameaddress(i32) nounwind readnone diff --git a/test/CodeGen/X86/x86-64-frameaddr.ll b/test/CodeGen/X86/x86-64-frameaddr.ll deleted file mode 100644 index 7d36a7af6aa..00000000000 --- a/test/CodeGen/X86/x86-64-frameaddr.ll +++ /dev/null @@ -1,15 +0,0 @@ -; RUN: llc < %s -march=x86-64 | FileCheck %s - -; CHECK: stack_end_address -; CHECK: {{movq.+rbp.*$}} -; CHECK: {{movq.+rbp.*$}} -; CHECK: ret - -define i64* @stack_end_address() nounwind { -entry: - tail call i8* @llvm.frameaddress( i32 0 ) - bitcast i8* %0 to i64* - ret i64* %1 -} - -declare i8* @llvm.frameaddress(i32) nounwind readnone diff --git a/test/CodeGen/X86/x86-frameaddr.ll b/test/CodeGen/X86/x86-frameaddr.ll deleted file mode 100644 index d5958745dff..00000000000 --- a/test/CodeGen/X86/x86-frameaddr.ll +++ /dev/null @@ -1,9 +0,0 @@ -; RUN: llc < %s -march=x86 | grep mov | grep ebp - -define i8* @t() nounwind { -entry: - %0 = tail call i8* @llvm.frameaddress(i32 0) - ret i8* %0 -} - -declare i8* @llvm.frameaddress(i32) nounwind readnone diff --git a/test/CodeGen/X86/x86-frameaddr2.ll b/test/CodeGen/X86/x86-frameaddr2.ll deleted file mode 100644 index c5091154152..00000000000 --- a/test/CodeGen/X86/x86-frameaddr2.ll +++ /dev/null @@ -1,9 +0,0 @@ -; RUN: llc < %s -march=x86 | grep mov | count 3 - -define i8* @t() nounwind { -entry: - %0 = tail call i8* @llvm.frameaddress(i32 2) - ret i8* %0 -} - -declare i8* @llvm.frameaddress(i32) nounwind readnone