[WebAssembly] Implement __builtin_frame_address.
Differential Revision: http://reviews.llvm.org/D17307
llvm-svn: 261032
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
index 27274c0..1c358b3 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
@@ -44,11 +44,11 @@
/// register.
bool WebAssemblyFrameLowering::hasFP(const MachineFunction &MF) const {
const MachineFrameInfo *MFI = MF.getFrameInfo();
- assert(!MFI->isFrameAddressTaken());
const auto *RegInfo =
MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo();
- return MFI->hasVarSizedObjects() || MFI->hasStackMap() ||
- MFI->hasPatchPoint() || RegInfo->needsStackRealignment(MF);
+ return MFI->isFrameAddressTaken() || MFI->hasVarSizedObjects() ||
+ MFI->hasStackMap() || MFI->hasPatchPoint() ||
+ RegInfo->needsStackRealignment(MF);
}
/// Under normal circumstances, when a frame pointer is not required, we reserve
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 2027e8b..c5ec506 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -542,9 +542,8 @@
case ISD::RETURNADDR: // Probably nothing meaningful can be returned here.
fail(DL, DAG, "WebAssembly hasn't implemented __builtin_return_address");
return SDValue();
- case ISD::FRAMEADDR: // TODO: Make this return the userspace frame address
- fail(DL, DAG, "WebAssembly hasn't implemented __builtin_frame_address");
- return SDValue();
+ case ISD::FRAMEADDR:
+ return LowerFRAMEADDR(Op, DAG);
case ISD::CopyToReg:
return LowerCopyToReg(Op, DAG);
}
@@ -579,6 +578,21 @@
return DAG.getTargetFrameIndex(FI, Op.getValueType());
}
+SDValue WebAssemblyTargetLowering::LowerFRAMEADDR(SDValue Op,
+ SelectionDAG &DAG) const {
+ // Non-zero depths are not supported by WebAssembly currently. Use the
+ // legalizer's default expansion, which is to return 0 (what this function is
+ // documented to do).
+ if (cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue() > 0)
+ return SDValue();
+
+ DAG.getMachineFunction().getFrameInfo()->setFrameAddressIsTaken(true);
+ EVT VT = Op.getValueType();
+ unsigned FP =
+ Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction());
+ return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), FP, VT);
+}
+
SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h
index 4aed2b1..5b538fd 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h
@@ -78,6 +78,7 @@
// Custom lowering hooks.
SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override;
SDValue LowerFrameIndex(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerExternalSymbol(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerBR_JT(SDValue Op, SelectionDAG &DAG) const;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp
index f38f635..76ea0d7 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp
@@ -108,11 +108,11 @@
}
}
// Allocate locals for used physical registers
- if (FrameInfo.getStackSize() > 0 || FrameInfo.adjustsStack()) {
+ bool HasFP = MF.getSubtarget().getFrameLowering()->hasFP(MF);
+ if (FrameInfo.getStackSize() > 0 || FrameInfo.adjustsStack() || HasFP) {
DEBUG(dbgs() << "PReg SP " << CurReg << "\n");
MFI.addPReg(WebAssembly::SP32, CurReg++);
}
- bool HasFP = MF.getSubtarget().getFrameLowering()->hasFP(MF);
if (HasFP) {
DEBUG(dbgs() << "PReg FP " << CurReg << "\n");
MFI.addPReg(WebAssembly::FP32, CurReg++);
diff --git a/llvm/test/CodeGen/WebAssembly/userstack.ll b/llvm/test/CodeGen/WebAssembly/userstack.ll
index b5e711f..2032507 100644
--- a/llvm/test/CodeGen/WebAssembly/userstack.ll
+++ b/llvm/test/CodeGen/WebAssembly/userstack.ll
@@ -181,4 +181,35 @@
ret void
}
+declare void @use_i8_star(i8*)
+declare i8* @llvm.frameaddress(i32)
+
+; Test __builtin_frame_address(0).
+; TODO: When the prolog/epilog sequences are optimized, refine these checks to
+; be more specific.
+
+; CHECK-LABEL: frameaddress_0:
+; CHECK: __stack_pointer
+; CHECK: load
+; CHECK: call use_i8_star
+; CHECK: __stack_pointer
+; CHECK: store
+define void @frameaddress_0() {
+ %t = call i8* @llvm.frameaddress(i32 0)
+ call void @use_i8_star(i8* %t)
+ ret void
+}
+
+; Test __builtin_frame_address(1).
+
+; CHECK-LABEL: frameaddress_1:
+; CHECK-NEXT: i32.const $push0=, 0{{$}}
+; CHECK-NEXT: call use_i8_star@FUNCTION, $pop0{{$}}
+; CHECK-NEXT: return{{$}}
+define void @frameaddress_1() {
+ %t = call i8* @llvm.frameaddress(i32 1)
+ call void @use_i8_star(i8* %t)
+ ret void
+}
+
; TODO: test over-aligned alloca