[llvm] r259220 - [WebAssembly] Support frame pointer

Derek Schuff via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 29 10:37:50 PST 2016


Author: dschuff
Date: Fri Jan 29 12:37:49 2016
New Revision: 259220

URL: http://llvm.org/viewvc/llvm-project?rev=259220&view=rev
Log:
[WebAssembly] Support frame pointer

Add support for frame pointer use in prolog/epilog.
Supports dynamic allocas but not yet over-aligned locals.
Target-independend CG generates SP updates, but we still need to write
back the SP value to memory when necessary.

Modified:
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp
    llvm/trunk/test/CodeGen/WebAssembly/userstack.ll

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp?rev=259220&r1=259219&r2=259220&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp Fri Jan 29 12:37:49 2016
@@ -70,6 +70,7 @@ static void adjustStackPointer(unsigned
                                const TargetInstrInfo* TII,
                                MachineBasicBlock::iterator InsertPt,
                                const DebugLoc& DL) {
+  assert((StackSize || !AdjustUp) && "Adjusting up by 0");
   auto &MRI = MF.getRegInfo();
   unsigned SPReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
   auto *SPSymbol = MF.createExternalSymbolName("__stack_pointer");
@@ -82,8 +83,8 @@ static void adjustStackPointer(unsigned
   auto *LoadMMO = new MachineMemOperand(MachinePointerInfo(),
                                         MachineMemOperand::MOLoad, 4, 4);
   BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::LOAD_I32), SPReg)
-      .addImm(0)
-      .addReg(SPReg)
+      .addImm(0) // offset
+      .addReg(SPReg) // addr
       .addImm(2) // p2align
       .addMemOperand(LoadMMO);
   // Add/Subtract the frame size
@@ -116,6 +117,9 @@ void WebAssemblyFrameLowering::eliminate
   unsigned Opc = I->getOpcode();
   bool IsDestroy = Opc == TII->getCallFrameDestroyOpcode();
   unsigned Amount = I->getOperand(0).getImm();
+  // TODO(dschuff): After we switch varargs to passing an explicit pointer
+  // rather than using an implicit call frame, assert here that Amount is 0
+  // and remove adjustStackPointer altogether.
   if (Amount)
     adjustStackPointer(Amount, IsDestroy, MF, MBB,
                        TII, I, DL);
@@ -128,23 +132,76 @@ void WebAssemblyFrameLowering::emitProlo
   auto *MFI = MF.getFrameInfo();
   assert(MFI->getCalleeSavedInfo().empty() &&
          "WebAssembly should not have callee-saved registers");
-  assert(!hasFP(MF) && "Functions needing frame pointers not yet supported");
+
   uint64_t StackSize = MFI->getStackSize();
-  if (!StackSize && (!MFI->adjustsStack() || MFI->getMaxCallFrameSize() == 0))
+  if (!StackSize && !MFI->adjustsStack())
     return;
 
   const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
+  auto &MRI = MF.getRegInfo();
 
   auto InsertPt = MBB.begin();
   DebugLoc DL;
 
-  adjustStackPointer(StackSize, false, MF, MBB, TII, InsertPt, DL);
+  unsigned SPReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
+  auto *SPSymbol = MF.createExternalSymbolName("__stack_pointer");
+  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), SPReg)
+      .addExternalSymbol(SPSymbol);
+  // This MachinePointerInfo should reference __stack_pointer as well but
+  // doesn't because MachinePointerInfo() takes a GV which we don't have for
+  // __stack_pointer. TODO: check if PseudoSourceValue::ExternalSymbolCallEntry
+  // is appropriate instead. (likewise for EmitEpologue below)
+  auto *LoadMMO = new MachineMemOperand(MachinePointerInfo(),
+                                        MachineMemOperand::MOLoad, 4, 4);
+  // Load the SP value.
+  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::LOAD_I32),
+          StackSize ? SPReg : WebAssembly::SP32)
+      .addImm(0) // offset
+      .addReg(SPReg) // addr
+      .addImm(2) // p2align
+      .addMemOperand(LoadMMO);
+
+  unsigned OffsetReg = 0;
+  if (StackSize) {
+    // Subtract the frame size
+    OffsetReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
+    BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
+        .addImm(StackSize);
+    BuildMI(MBB, InsertPt, DL,
+            TII->get(WebAssembly::SUB_I32),
+            WebAssembly::SP32)
+        .addReg(SPReg)
+        .addReg(OffsetReg);
+  }
+  if (hasFP(MF)) {
+    // Unlike most conventional targets (where FP points to the saved FP),
+    // FP points to the bottom of the fixed-size locals, so we can use positive
+    // offsets in load/store instructions.
+    BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY_LOCAL_I32),
+            WebAssembly::FP32)
+        .addReg(WebAssembly::SP32);
+  }
+  if (StackSize) {
+    assert(OffsetReg);
+  // The SP32 register now has the new stacktop. Also write it back to memory.
+  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
+      .addExternalSymbol(SPSymbol);
+  auto *MMO = new MachineMemOperand(MachinePointerInfo(),
+                                    MachineMemOperand::MOStore, 4, 4);
+  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::STORE_I32), WebAssembly::SP32)
+      .addImm(0)
+      .addReg(OffsetReg)
+      .addImm(2) // p2align
+      .addReg(WebAssembly::SP32)
+      .addMemOperand(MMO);
+  }
 }
 
 void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF,
                                             MachineBasicBlock &MBB) const {
-  uint64_t StackSize = MF.getFrameInfo()->getStackSize();
-  if (!StackSize)
+  auto *MFI = MF.getFrameInfo();
+  uint64_t StackSize = MFI->getStackSize();
+  if (!StackSize && !MFI->adjustsStack())
     return;
   const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
   auto &MRI = MF.getRegInfo();
@@ -156,14 +213,17 @@ void WebAssemblyFrameLowering::emitEpilo
     DL = InsertPt->getDebugLoc();
   }
 
-  // Restore the stack pointer. Without FP its value is just SP32 - stacksize
-  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
-      .addImm(StackSize);
+  // Restore the stack pointer. If we had fixed-size locals, add the offset
+  // subtracted in the prolog.
+  if (StackSize) {
+    BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
+        .addImm(StackSize);
+    BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::ADD_I32), WebAssembly::SP32)
+        .addReg(hasFP(MF) ? WebAssembly::FP32 : WebAssembly::SP32)
+        .addReg(OffsetReg);
+  }
+
   auto *SPSymbol = MF.createExternalSymbolName("__stack_pointer");
-  // TODO: Fold this add into the const offset field of the store.
-  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::ADD_I32), WebAssembly::SP32)
-      .addReg(WebAssembly::SP32)
-      .addReg(OffsetReg);
   // Re-use OffsetReg to hold the address of the stacktop
   BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), OffsetReg)
       .addExternalSymbol(SPSymbol);
@@ -173,6 +233,6 @@ void WebAssemblyFrameLowering::emitEpilo
       .addImm(0)
       .addReg(OffsetReg)
       .addImm(2) // p2align
-      .addReg(WebAssembly::SP32)
+      .addReg((!StackSize && hasFP(MF)) ? WebAssembly::FP32 : WebAssembly::SP32)
       .addMemOperand(MMO);
 }

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp?rev=259220&r1=259219&r2=259220&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp Fri Jan 29 12:37:49 2016
@@ -58,7 +58,7 @@ void WebAssemblyInstrInfo::copyPhysReg(M
   const TargetRegisterClass *RC =
       TargetRegisterInfo::isVirtualRegister(DestReg)
           ? MRI.getRegClass(DestReg)
-          : MRI.getTargetRegisterInfo()->getMinimalPhysRegClass(SrcReg);
+          : MRI.getTargetRegisterInfo()->getMinimalPhysRegClass(DestReg);
 
   unsigned CopyLocalOpcode;
   if (RC == &WebAssembly::I32RegClass)

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp?rev=259220&r1=259219&r2=259220&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp Fri Jan 29 12:37:49 2016
@@ -108,10 +108,15 @@ bool WebAssemblyRegNumbering::runOnMachi
     }
   }
   // Allocate locals for used physical registers
-  if (FrameInfo.getStackSize() > 0) {
+  if (FrameInfo.getStackSize() > 0 || FrameInfo.adjustsStack()) {
     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++);
+  }
 
   return true;
 }

Modified: llvm/trunk/test/CodeGen/WebAssembly/userstack.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/userstack.ll?rev=259220&r1=259219&r2=259220&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/userstack.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/userstack.ll Fri Jan 29 12:37:49 2016
@@ -119,9 +119,36 @@ define void @allocarray_inbounds() {
 
 ; CHECK-LABEL: dynamic_alloca:
 define void @dynamic_alloca(i32 %alloc) {
- ; TODO: Support frame pointers
- ;%r = alloca i32, i32 %alloc
- ;store i32 0, i32* %r
+ ; CHECK: i32.const [[L0:.+]]=, __stack_pointer
+ ; CHECK-NEXT: i32.load [[SP:.+]]=, 0([[L0]])
+ ; CHECK-NEXT: copy_local [[FP:.+]]=, [[SP]]
+ ; Target independent codegen bumps the stack pointer
+ ; FIXME: we need to write the value back to memory
+ %r = alloca i32, i32 %alloc
+ ; Target-independent codegen also calculates the store addr
+ store i32 0, i32* %r
+ ; CHECK: i32.const [[L3:.+]]=, __stack_pointer
+ ; CHECK-NEXT: i32.store [[SP]]=, 0([[L3]]), [[FP]]
+ ret void
+}
+
+
+; CHECK-LABEL: dynamic_static_alloca:
+define void @dynamic_static_alloca(i32 %alloc) {
+ ; CHECK: i32.const [[L0:.+]]=, __stack_pointer
+ ; CHECK-NEXT: i32.load [[L0]]=, 0([[L0]])
+ ; CHECK-NEXT: i32.const [[L2:.+]]=, 16
+ ; CHECK-NEXT: i32.sub [[SP:.+]]=, [[L0]], [[L2]]
+ ; CHECK-NEXT: copy_local [[FP:.+]]=, [[SP]]
+ ; CHECK-NEXT: i32.const [[L3:.+]]=, __stack_pointer
+ ; CHECK-NEXT: i32.store {{.*}}=, 0([[L3]]), [[SP]]
+ %r1 = alloca i32
+ %r = alloca i32, i32 %alloc
+ store i32 0, i32* %r
+ ; CHECK: i32.const [[L3:.+]]=, 16
+ ; CHECK: i32.add [[SP]]=, [[FP]], [[L3]]
+ ; CHECK: i32.const [[L4:.+]]=, __stack_pointer
+ ; CHECK-NEXT: i32.store [[SP]]=, 0([[L4]]), [[SP]]
  ret void
 }
 ; TODO: test aligned alloc




More information about the llvm-commits mailing list