[llvm] r286160 - [WebAssembly] Emit a BasePointer when we have overly-aligned stack objects

Derek Schuff via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 7 14:00:48 PST 2016


Author: dschuff
Date: Mon Nov  7 16:00:48 2016
New Revision: 286160

URL: http://llvm.org/viewvc/llvm-project?rev=286160&view=rev
Log:
[WebAssembly] Emit a BasePointer when we have overly-aligned stack objects

Because we shift the stack pointer by an unknown amount, we need an
additional pointer. In the case where we have variable-size objects
as well, we can't reuse the frame pointer, thus three pointers.

Patch by Jacob Gravelle

Differential Revision: https://reviews.llvm.org/D26263

Added:
    llvm/trunk/test/CodeGen/WebAssembly/stack-alignment.ll
Modified:
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.h
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp?rev=286160&r1=286159&r2=286160&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp Mon Nov  7 16:00:48 2016
@@ -37,15 +37,34 @@ using namespace llvm;
 // TODO: wasm64
 // TODO: Emit TargetOpcode::CFI_INSTRUCTION instructions
 
+/// We need a base pointer in the case of having items on the stack that
+/// require stricter alignment than the stack pointer itself.  Because we need
+/// to shift the stack pointer by some unknown amount to force the alignment,
+/// we need to record the value of the stack pointer on entry to the function.
+bool WebAssemblyFrameLowering::hasBP(
+    const MachineFunction &MF) const {
+  const auto *RegInfo =
+      MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo();
+  return RegInfo->needsStackRealignment(MF);
+}
+
 /// Return true if the specified function should have a dedicated frame pointer
 /// register.
 bool WebAssemblyFrameLowering::hasFP(const MachineFunction &MF) const {
   const MachineFrameInfo &MFI = MF.getFrameInfo();
-  const auto *RegInfo =
-      MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo();
-  return MFI.isFrameAddressTaken() || MFI.hasVarSizedObjects() ||
-         MFI.hasStackMap() || MFI.hasPatchPoint() ||
-         RegInfo->needsStackRealignment(MF);
+
+  // When we have var-sized objects, we move the stack pointer by an unknown
+  // amount, and need to emit a frame pointer to restore the stack to where we
+  // were on function entry.
+  // If we already need a base pointer, we use that to fix up the stack pointer.
+  // If there are no fixed-size objects, we would have no use of a frame
+  // pointer, and thus should not emit one.
+  bool HasFixedSizedObjects = MFI.getStackSize() > 0;
+  bool NeedsFixedReference = !hasBP(MF) || HasFixedSizedObjects;
+
+  return MFI.isFrameAddressTaken() ||
+         (MFI.hasVarSizedObjects() && NeedsFixedReference) ||
+         MFI.hasStackMap() || MFI.hasPatchPoint();
 }
 
 /// Under normal circumstances, when a frame pointer is not required, we reserve
@@ -107,7 +126,7 @@ MachineBasicBlock::iterator
 WebAssemblyFrameLowering::eliminateCallFramePseudoInstr(
     MachineFunction &MF, MachineBasicBlock &MBB,
     MachineBasicBlock::iterator I) const {
-  assert(!I->getOperand(0).getImm() && hasFP(MF) &&
+  assert(!I->getOperand(0).getImm() && (hasFP(MF) || hasBP(MF)) &&
          "Call frame pseudos should only be used for dynamic stack adjustment");
   const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
   if (I->getOpcode() == TII->getCallFrameDestroyOpcode() &&
@@ -137,7 +156,9 @@ void WebAssemblyFrameLowering::emitProlo
   const TargetRegisterClass *PtrRC =
       MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
   unsigned Zero = MRI.createVirtualRegister(PtrRC);
-  unsigned SPReg = MRI.createVirtualRegister(PtrRC);
+  unsigned SPReg = WebAssembly::SP32;
+  if (StackSize)
+    SPReg = MRI.createVirtualRegister(PtrRC);
   const char *ES = "__stack_pointer";
   auto *SPSymbol = MF.createExternalSymbolName(ES);
   BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), Zero)
@@ -146,13 +167,20 @@ void WebAssemblyFrameLowering::emitProlo
       MachinePointerInfo(MF.getPSVManager().getExternalSymbolCallEntry(ES)),
       MachineMemOperand::MOLoad, 4, 4);
   // Load the SP value.
-  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::LOAD_I32),
-          StackSize ? SPReg : (unsigned)WebAssembly::SP32)
+  BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::LOAD_I32), SPReg)
       .addImm(2)       // p2align
       .addExternalSymbol(SPSymbol)
       .addReg(Zero)    // addr
       .addMemOperand(LoadMMO);
 
+  bool HasBP = hasBP(MF);
+  if (HasBP) {
+    auto FI = MF.getInfo<WebAssemblyFunctionInfo>();
+    unsigned BasePtr = MRI.createVirtualRegister(PtrRC);
+    FI->setBasePointerVreg(BasePtr);
+    BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY), BasePtr)
+        .addReg(SPReg);
+  }
   if (StackSize) {
     // Subtract the frame size
     unsigned OffsetReg = MRI.createVirtualRegister(PtrRC);
@@ -163,6 +191,18 @@ void WebAssemblyFrameLowering::emitProlo
         .addReg(SPReg)
         .addReg(OffsetReg);
   }
+  if (HasBP) {
+    unsigned BitmaskReg = MRI.createVirtualRegister(PtrRC);
+    unsigned Alignment = MFI.getMaxAlignment();
+    assert((1 << countTrailingZeros(Alignment)) == Alignment &&
+      "Alignment must be a power of 2");
+    BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), BitmaskReg)
+        .addImm((int)~(Alignment - 1));
+    BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::AND_I32),
+            WebAssembly::SP32)
+        .addReg(WebAssembly::SP32)
+        .addReg(BitmaskReg);
+  }
   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
@@ -193,7 +233,10 @@ void WebAssemblyFrameLowering::emitEpilo
   // subtracted in the prolog.
   unsigned SPReg = 0;
   MachineBasicBlock::iterator InsertAddr = InsertPt;
-  if (StackSize) {
+  if (hasBP(MF)) {
+    auto FI = MF.getInfo<WebAssemblyFunctionInfo>();
+    SPReg = FI->getBasePointerVreg();
+  } else if (StackSize) {
     const TargetRegisterClass *PtrRC =
         MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
     unsigned OffsetReg = MRI.createVirtualRegister(PtrRC);

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.h?rev=286160&r1=286159&r2=286160&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.h (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.h Mon Nov  7 16:00:48 2016
@@ -46,6 +46,7 @@ class WebAssemblyFrameLowering final : p
   bool hasReservedCallFrame(const MachineFunction &MF) const override;
 
  private:
+  bool hasBP(const MachineFunction &MF) const;
   bool needsSP(const MachineFunction &MF, const MachineFrameInfo &MFI) const;
   bool needsSPWriteback(const MachineFunction &MF,
                         const MachineFrameInfo &MFI) const;

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h?rev=286160&r1=286159&r2=286160&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h Mon Nov  7 16:00:48 2016
@@ -46,6 +46,10 @@ class WebAssemblyFunctionInfo final : pu
   // TLI::LowerVASTART
   unsigned VarargVreg = -1U;
 
+  // A virtual register holding the base pointer for functions that have
+  // overaligned values on the user stack.
+  unsigned BasePtrVreg = -1U;
+
  public:
   explicit WebAssemblyFunctionInfo(MachineFunction &MF) : MF(MF) {}
   ~WebAssemblyFunctionInfo() override;
@@ -65,6 +69,12 @@ class WebAssemblyFunctionInfo final : pu
   }
   void setVarargBufferVreg(unsigned Reg) { VarargVreg = Reg; }
 
+  unsigned getBasePointerVreg() const {
+    assert(BasePtrVreg != -1U && "Base ptr vreg hasn't been set");
+    return BasePtrVreg;
+  }
+  void setBasePointerVreg(unsigned Reg) { BasePtrVreg = Reg; }
+
   static const unsigned UnusedReg = -1u;
 
   void stackifyVReg(unsigned VReg) {

Added: llvm/trunk/test/CodeGen/WebAssembly/stack-alignment.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/stack-alignment.ll?rev=286160&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/stack-alignment.ll (added)
+++ llvm/trunk/test/CodeGen/WebAssembly/stack-alignment.ll Mon Nov  7 16:00:48 2016
@@ -0,0 +1,137 @@
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+declare void @somefunc(i32*)
+
+; CHECK-LABEL: underalign:
+; CHECK:      i32.load  $push[[L1:.+]]=, __stack_pointer{{.+}}
+; CHECK-NEXT: i32.const $push[[L2:.+]]=, 16
+; CHECK-NEXT: i32.sub   $push[[L10:.+]]=, $pop[[L1]], $pop[[L2]]
+; CHECK-NEXT: tee_local $push{{.+}}=, $[[SP:.+]]=, $pop[[L10]]
+
+; CHECK:      i32.add   $push[[underaligned:.+]]=, $[[SP]], $pop{{.+}}
+; CHECK-NEXT: call      somefunc at FUNCTION, $pop[[underaligned]]
+
+; CHECK:      i32.add   $push[[L5:.+]]=, $[[SP]], $pop{{.+}}
+; CHECK-NEXT: i32.store __stack_pointer($pop{{.+}}), $pop[[L5]]
+define void @underalign() {
+entry:
+  %underaligned = alloca i32, align 8
+  call void @somefunc(i32* %underaligned)
+  ret void
+}
+
+; CHECK-LABEL: overalign:
+; CHECK:      i32.load   $push[[L10:.+]]=, __stack_pointer
+; CHECK-NEXT: tee_local  $push[[L9:.+]]=, $[[BP:.+]]=, $pop[[L10]]
+; CHECK-NEXT: i32.const  $push[[L2:.+]]=, 32
+; CHECK-NEXT: i32.sub    $push[[L8:.+]]=, $pop[[L9]], $pop[[L2]]
+; CHECK-NEXT: i32.const  $push[[L3:.+]]=, -32
+; CHECK-NEXT: i32.and    $push[[L7:.+]]=, $pop[[L8]], $pop[[L3]]
+; CHECK-NEXT: tee_local  $push{{.+}}=, $[[SP:.+]]=, $pop[[L7]]
+
+; CHECK:      call       somefunc at FUNCTION, $[[SP]]
+
+; CHECK:      copy_local $push[[L5:.+]]=, $[[BP]]
+; CHECK-NEXT: i32.store  __stack_pointer($pop{{.+}}), $pop[[L5]]
+define void @overalign() {
+entry:
+  %overaligned = alloca i32, align 32
+  call void @somefunc(i32* %overaligned)
+  ret void
+}
+
+; CHECK-LABEL: over_and_normal_align:
+; CHECK:      i32.load   $push[[L14:.+]]=, __stack_pointer
+; CHECK-NEXT: tee_local  $push[[L13:.+]]=, $[[BP:.+]]=, $pop[[L14]]
+; CHECK:      i32.sub    $push[[L12:.+]]=, $pop[[L13]], $pop{{.+}}
+; CHECK:      i32.and    $push[[L11:.+]]=, $pop[[L12]], $pop{{.+}}
+; CHECK-NEXT: tee_local  $push{{.+}}=, $[[SP]]=, $pop[[L11]]
+
+; CHECK:      i32.add    $push[[L6:.+]]=, $[[SP]], $pop{{.+}}
+; CHECK-NEXT: call       somefunc at FUNCTION, $pop[[L6]]
+; CHECK:      i32.add    $push[[L8:.+]]=, $[[SP]], $pop{{.+}}
+; CHECK-NEXT: call       somefunc at FUNCTION, $pop[[L8]]
+
+; CHECK:      copy_local $push[[L9:.+]]=, $[[BP]]
+; CHECK-NEXT: i32.store  __stack_pointer({{.+}}), $pop[[L9]]
+define void @over_and_normal_align() {
+entry:
+  %over = alloca i32, align 32
+  %normal = alloca i32
+  call void @somefunc(i32* %over)
+  call void @somefunc(i32* %normal)
+  ret void
+}
+
+; CHECK-LABEL: dynamic_overalign:
+; CHECK:      i32.load   $push[[L18:.+]]=, __stack_pointer
+; CHECK-NEXT: tee_local  $push[[L17:.+]]=, $[[SP:.+]]=, $pop[[L18]]
+; CHECK-NEXT: copy_local $[[BP:.+]]=, $pop[[L17]]
+; CHECK:      tee_local  $push{{.+}}=, $[[SP_2:.+]]=, $pop{{.+}}
+
+; CHECK:      call       somefunc at FUNCTION, $[[SP_2]]
+
+; CHECK: i32.store __stack_pointer($pop{{.+}}), $[[BP]]
+define void @dynamic_overalign(i32 %num) {
+entry:
+  %dynamic = alloca i32, i32 %num, align 32
+  call void @somefunc(i32* %dynamic)
+  ret void
+}
+
+; CHECK-LABEL: overalign_and_dynamic:
+; CHECK:      i32.load   $push[[L21:.+]]=, __stack_pointer
+; CHECK-NEXT: tee_local  $push[[L20:.+]]=, $[[BP:.+]]=, $pop[[L21]]
+; CHECK:      i32.sub    $push[[L19:.+]]=, $pop[[L20]], $pop{{.+}}
+; CHECK:      i32.and    $push[[L18:.+]]=, $pop[[L19]], $pop{{.+}}
+; CHECK:      tee_local  $push{{.+}}=, $[[FP:.+]]=, $pop[[L18]]
+; CHECK:      i32.sub    $push[[L16:.+]]=, $[[FP]], $pop{{.+}}
+; CHECK-NEXT: tee_local  $push{{.+}}=, $[[SP:.+]]=, $pop[[L16]]
+
+; CHECK:      copy_local $push[[over:.+]]=, $[[FP]]
+; CHECK-NEXT: call       somefunc at FUNCTION, $pop[[over]]
+; CHECK-NEXT: call       somefunc at FUNCTION, $[[SP]]
+
+; CHECK:      copy_local $push[[L12:.+]]=, $[[BP]]
+; CHECK-NEXT: i32.store  __stack_pointer($pop{{.+}}), $pop[[L12]]
+define void @overalign_and_dynamic(i32 %num) {
+entry:
+  %over = alloca i32, align 32
+  %dynamic = alloca i32, i32 %num
+  call void @somefunc(i32* %over)
+  call void @somefunc(i32* %dynamic)
+  ret void
+}
+
+; CHECK-LABEL: overalign_static_and_dynamic:
+; CHECK:      i32.load   $push[[L26:.+]]=, __stack_pointer
+; CHECK-NEXT: tee_local  $push[[L25:.+]]=, $[[BP:.+]]=, $pop[[L26]]
+; CHECK:      i32.sub    $push[[L24:.+]]=, $pop[[L25]], $pop{{.+}}
+; CHECK:      i32.and    $push[[L23:.+]]=, $pop[[L24]], $pop{{.+}}
+; CHECK:      tee_local  $push{{.+}}=, $[[FP:.+]]=, $pop[[L23]]
+; CHECK:      i32.sub    $push[[L21:.+]]=, $[[FP]], $pop{{.+}}
+; CHECK-NEXT: tee_local  $push{{.+}}=, $[[SP:.+]]=, $pop[[L21]]
+
+; CHECK:      copy_local $push[[L19:.+]]=, $[[FP]]
+; CHECK:      tee_local  $push[[L18:.+]]=, $[[FP_2:.+]]=, $pop[[L19]]
+; CHECK:      i32.add    $push[[over:.+]]=, $pop[[L18]], $pop{{.+}}
+; CHECK-NEXT: call       somefunc at FUNCTION, $pop[[over]]
+; CHECK:      call       somefunc at FUNCTION, $[[SP]]
+; CHECK:      i32.add    $push[[static:.+]]=, $[[FP_2]], $pop{{.+}}
+; CHECK-NEXT: call       somefunc at FUNCTION, $pop[[static]]
+
+; CHECK:      copy_local $push[[L16:.+]]=, $[[BP]]
+; CHECK-NEXT: i32.store  __stack_pointer({{.+}}), $pop[[L16]]
+define void @overalign_static_and_dynamic(i32 %num) {
+entry:
+  %over = alloca i32, align 32
+  %dynamic = alloca i32, i32 %num
+  %static = alloca i32
+  call void @somefunc(i32* %over)
+  call void @somefunc(i32* %dynamic)
+  call void @somefunc(i32* %static)
+  ret void
+}




More information about the llvm-commits mailing list