OSDN Git Service

Merged addProlog and addEpilog on x86.
authorDavid Sehr <sehr@chromium.org>
Thu, 21 Jan 2016 16:09:27 +0000 (08:09 -0800)
committerDavid Sehr <sehr@chromium.org>
Thu, 21 Jan 2016 16:09:27 +0000 (08:09 -0800)
BUG=
R=jpp@chromium.org

Review URL: https://codereview.chromium.org/1616483003 .

src/IceTargetLoweringX8632.cpp
src/IceTargetLoweringX8632.h
src/IceTargetLoweringX8664.cpp
src/IceTargetLoweringX8664.h
src/IceTargetLoweringX86Base.h
src/IceTargetLoweringX86BaseImpl.h

index c154901..e9164f6 100644 (file)
@@ -141,6 +141,67 @@ void TargetX8632::_sub_sp(Operand *Adjustment) {
   _sub(esp, Adjustment);
 }
 
+void TargetX8632::_link_bp() {
+  Variable *ebp = getPhysicalRegister(Traits::RegisterSet::Reg_ebp);
+  Variable *esp = getPhysicalRegister(Traits::RegisterSet::Reg_esp);
+  _push(ebp);
+  _mov(ebp, esp);
+  // Keep ebp live for late-stage liveness analysis (e.g. asm-verbose mode).
+  Context.insert<InstFakeUse>(ebp);
+}
+
+void TargetX8632::_unlink_bp() {
+  Variable *esp = getPhysicalRegister(Traits::RegisterSet::Reg_esp);
+  Variable *ebp = getPhysicalRegister(Traits::RegisterSet::Reg_ebp);
+  // For late-stage liveness analysis (e.g. asm-verbose mode), adding a fake
+  // use of esp before the assignment of esp=ebp keeps previous esp
+  // adjustments from being dead-code eliminated.
+  Context.insert<InstFakeUse>(esp);
+  _mov(esp, ebp);
+  _pop(ebp);
+}
+
+void TargetX8632::_push_reg(Variable *Reg) { _push(Reg); }
+
+void TargetX8632::emitGetIP(CfgNode *Node) {
+  // If there is a non-deleted InstX86GetIP instruction, we need to move it to
+  // the point after the stack frame has stabilized but before
+  // register-allocated in-args are copied into their home registers.  It would
+  // be slightly faster to search for the GetIP instruction before other prolog
+  // instructions are inserted, but it's more clear to do the whole
+  // transformation in a single place.
+  Traits::Insts::GetIP *GetIPInst = nullptr;
+  if (Ctx->getFlags().getUseNonsfi()) {
+    for (Inst &Instr : Node->getInsts()) {
+      if (auto *GetIP = llvm::dyn_cast<Traits::Insts::GetIP>(&Instr)) {
+        if (!Instr.isDeleted())
+          GetIPInst = GetIP;
+        break;
+      }
+    }
+  }
+  // Delete any existing InstX86GetIP instruction and reinsert it here.  Also,
+  // insert the call to the helper function and the spill to the stack, to
+  // simplify emission.
+  if (GetIPInst) {
+    GetIPInst->setDeleted();
+    Variable *Dest = GetIPInst->getDest();
+    Variable *CallDest =
+        Dest->hasReg() ? Dest
+                       : getPhysicalRegister(Traits::RegisterSet::Reg_eax);
+    // Call the getIP_<reg> helper.
+    IceString RegName = Traits::getRegName(CallDest->getRegNum());
+    Constant *CallTarget = Ctx->getConstantExternSym(H_getIP_prefix + RegName);
+    Context.insert<Traits::Insts::Call>(CallDest, CallTarget);
+    // Insert a new version of InstX86GetIP.
+    Context.insert<Traits::Insts::GetIP>(CallDest);
+    // Spill the register to its home stack location if necessary.
+    if (!Dest->hasReg()) {
+      _mov(Dest, CallDest);
+    }
+  }
+}
+
 void TargetX8632::lowerIndirectJump(Variable *JumpTarget) {
   AutoBundle _(this);
 
@@ -195,352 +256,7 @@ Variable *TargetX8632::moveReturnValueToRegister(Operand *Value,
   }
 }
 
-void TargetX8632::addProlog(CfgNode *Node) {
-  // Stack frame layout:
-  //
-  // +------------------------+
-  // | 1. return address      |
-  // +------------------------+
-  // | 2. preserved registers |
-  // +------------------------+
-  // | 3. padding             |
-  // +------------------------+
-  // | 4. global spill area   |
-  // +------------------------+
-  // | 5. padding             |
-  // +------------------------+
-  // | 6. local spill area    |
-  // +------------------------+
-  // | 7. padding             |
-  // +------------------------+
-  // | 8. allocas             |
-  // +------------------------+
-  // | 9. padding             |
-  // +------------------------+
-  // | 10. out args           |
-  // +------------------------+ <--- StackPointer
-  //
-  // The following variables record the size in bytes of the given areas:
-  //  * X86_RET_IP_SIZE_BYTES:  area 1
-  //  * PreservedRegsSizeBytes: area 2
-  //  * SpillAreaPaddingBytes:  area 3
-  //  * GlobalsSize:            area 4
-  //  * GlobalsAndSubsequentPaddingSize: areas 4 - 5
-  //  * LocalsSpillAreaSize:    area 6
-  //  * SpillAreaSizeBytes:     areas 3 - 10
-  //  * maxOutArgsSizeBytes():  area 10
-
-  // Determine stack frame offsets for each Variable without a register
-  // assignment. This can be done as one variable per stack slot. Or, do
-  // coalescing by running the register allocator again with an infinite set of
-  // registers (as a side effect, this gives variables a second chance at
-  // physical register assignment).
-  //
-  // A middle ground approach is to leverage sparsity and allocate one block of
-  // space on the frame for globals (variables with multi-block lifetime), and
-  // one block to share for locals (single-block lifetime).
-
-  Context.init(Node);
-  Context.setInsertPoint(Context.getCur());
-
-  llvm::SmallBitVector CalleeSaves =
-      getRegisterSet(RegSet_CalleeSave, RegSet_None);
-  RegsUsed = llvm::SmallBitVector(CalleeSaves.size());
-  VarList SortedSpilledVariables, VariablesLinkedToSpillSlots;
-  size_t GlobalsSize = 0;
-  // If there is a separate locals area, this represents that area. Otherwise
-  // it counts any variable not counted by GlobalsSize.
-  SpillAreaSizeBytes = 0;
-  // If there is a separate locals area, this specifies the alignment for it.
-  uint32_t LocalsSlotsAlignmentBytes = 0;
-  // The entire spill locations area gets aligned to largest natural alignment
-  // of the variables that have a spill slot.
-  uint32_t SpillAreaAlignmentBytes = 0;
-  // A spill slot linked to a variable with a stack slot should reuse that
-  // stack slot.
-  std::function<bool(Variable *)> TargetVarHook =
-      [&VariablesLinkedToSpillSlots](Variable *Var) {
-        if (auto *SpillVar =
-                llvm::dyn_cast<typename Traits::SpillVariable>(Var)) {
-          assert(Var->mustNotHaveReg());
-          if (SpillVar->getLinkedTo() && !SpillVar->getLinkedTo()->hasReg()) {
-            VariablesLinkedToSpillSlots.push_back(Var);
-            return true;
-          }
-        }
-        return false;
-      };
-
-  // Compute the list of spilled variables and bounds for GlobalsSize, etc.
-  getVarStackSlotParams(SortedSpilledVariables, RegsUsed, &GlobalsSize,
-                        &SpillAreaSizeBytes, &SpillAreaAlignmentBytes,
-                        &LocalsSlotsAlignmentBytes, TargetVarHook);
-  uint32_t LocalsSpillAreaSize = SpillAreaSizeBytes;
-  SpillAreaSizeBytes += GlobalsSize;
-
-  // Add push instructions for preserved registers.
-  uint32_t NumCallee = 0;
-  size_t PreservedRegsSizeBytes = 0;
-  llvm::SmallBitVector Pushed(CalleeSaves.size());
-  for (SizeT i = 0; i < CalleeSaves.size(); ++i) {
-    SizeT Canonical = Traits::getBaseReg(i);
-    if (CalleeSaves[i] && RegsUsed[i]) {
-      Pushed[Canonical] = true;
-    }
-  }
-  for (SizeT i = 0; i < Pushed.size(); ++i) {
-    if (Pushed[i]) {
-      ++NumCallee;
-      PreservedRegsSizeBytes += typeWidthInBytes(IceType_i32);
-      _push(getPhysicalRegister(i));
-    }
-  }
-  Ctx->statsUpdateRegistersSaved(NumCallee);
-
-  // Generate "push ebp; mov ebp, esp"
-  if (IsEbpBasedFrame) {
-    assert((RegsUsed & getRegisterSet(RegSet_FramePointer, RegSet_None))
-               .count() == 0);
-    PreservedRegsSizeBytes += typeWidthInBytes(IceType_i32);
-    Variable *ebp = getPhysicalRegister(Traits::RegisterSet::Reg_ebp);
-    Variable *esp = getPhysicalRegister(Traits::RegisterSet::Reg_esp);
-    _push(ebp);
-    _mov(ebp, esp);
-    // Keep ebp live for late-stage liveness analysis (e.g. asm-verbose mode).
-    Context.insert<InstFakeUse>(ebp);
-  }
-
-  // Align the variables area. SpillAreaPaddingBytes is the size of the region
-  // after the preserved registers and before the spill areas.
-  // LocalsSlotsPaddingBytes is the amount of padding between the globals and
-  // locals area if they are separate.
-  assert(SpillAreaAlignmentBytes <= Traits::X86_STACK_ALIGNMENT_BYTES);
-  assert(LocalsSlotsAlignmentBytes <= SpillAreaAlignmentBytes);
-  uint32_t SpillAreaPaddingBytes = 0;
-  uint32_t LocalsSlotsPaddingBytes = 0;
-  alignStackSpillAreas(Traits::X86_RET_IP_SIZE_BYTES + PreservedRegsSizeBytes,
-                       SpillAreaAlignmentBytes, GlobalsSize,
-                       LocalsSlotsAlignmentBytes, &SpillAreaPaddingBytes,
-                       &LocalsSlotsPaddingBytes);
-  SpillAreaSizeBytes += SpillAreaPaddingBytes + LocalsSlotsPaddingBytes;
-  uint32_t GlobalsAndSubsequentPaddingSize =
-      GlobalsSize + LocalsSlotsPaddingBytes;
-
-  // Functions returning scalar floating point types may need to convert values
-  // from an in-register xmm value to the top of the x87 floating point stack.
-  // This is done by a movp[sd] and an fld[sd].  Ensure there is enough scratch
-  // space on the stack for this.
-  const Type ReturnType = Func->getReturnType();
-  if (isScalarFloatingType(ReturnType)) {
-    // Avoid misaligned double-precicion load/store.
-    NeedsStackAlignment = true;
-    SpillAreaSizeBytes =
-        std::max(typeWidthInBytesOnStack(ReturnType), SpillAreaSizeBytes);
-  }
-
-  // Align esp if necessary.
-  if (NeedsStackAlignment) {
-    uint32_t StackOffset =
-        Traits::X86_RET_IP_SIZE_BYTES + PreservedRegsSizeBytes;
-    uint32_t StackSize =
-        Traits::applyStackAlignment(StackOffset + SpillAreaSizeBytes);
-    StackSize = Traits::applyStackAlignment(StackSize + maxOutArgsSizeBytes());
-    SpillAreaSizeBytes = StackSize - StackOffset;
-  } else {
-    SpillAreaSizeBytes += maxOutArgsSizeBytes();
-  }
-
-  // Combine fixed allocations into SpillAreaSizeBytes if we are emitting the
-  // fixed allocations in the prolog.
-  if (PrologEmitsFixedAllocas)
-    SpillAreaSizeBytes += FixedAllocaSizeBytes;
-  if (SpillAreaSizeBytes) {
-    // Generate "sub esp, SpillAreaSizeBytes"
-    _sub(getPhysicalRegister(Traits::RegisterSet::Reg_esp),
-         Ctx->getConstantInt32(SpillAreaSizeBytes));
-    // If the fixed allocas are aligned more than the stack frame, align the
-    // stack pointer accordingly.
-    if (PrologEmitsFixedAllocas &&
-        FixedAllocaAlignBytes > Traits::X86_STACK_ALIGNMENT_BYTES) {
-      assert(IsEbpBasedFrame);
-      _and(getPhysicalRegister(Traits::RegisterSet::Reg_esp),
-           Ctx->getConstantInt32(-FixedAllocaAlignBytes));
-    }
-  }
-
-  // Account for known-frame-offset alloca instructions that were not already
-  // combined into the prolog.
-  if (!PrologEmitsFixedAllocas)
-    SpillAreaSizeBytes += FixedAllocaSizeBytes;
-
-  Ctx->statsUpdateFrameBytes(SpillAreaSizeBytes);
-
-  // Fill in stack offsets for stack args, and copy args into registers for
-  // those that were register-allocated. Args are pushed right to left, so
-  // Arg[0] is closest to the stack/frame pointer.
-  Variable *FramePtr = getPhysicalRegister(getFrameOrStackReg());
-  size_t BasicFrameOffset =
-      PreservedRegsSizeBytes + Traits::X86_RET_IP_SIZE_BYTES;
-  if (!IsEbpBasedFrame)
-    BasicFrameOffset += SpillAreaSizeBytes;
-
-  // If there is a non-deleted InstX86GetIP instruction, we need to move it to
-  // the point after the stack frame has stabilized but before
-  // register-allocated in-args are copied into their home registers.  It would
-  // be slightly faster to search for the GetIP instruction before other prolog
-  // instructions are inserted, but it's more clear to do the whole
-  // transformation in a single place.
-  Traits::Insts::GetIP *GetIPInst = nullptr;
-  if (Ctx->getFlags().getUseNonsfi()) {
-    for (Inst &Instr : Node->getInsts()) {
-      if (auto *GetIP = llvm::dyn_cast<Traits::Insts::GetIP>(&Instr)) {
-        if (!Instr.isDeleted())
-          GetIPInst = GetIP;
-        break;
-      }
-    }
-  }
-  // Delete any existing InstX86GetIP instruction and reinsert it here.  Also,
-  // insert the call to the helper function and the spill to the stack, to
-  // simplify emission.
-  if (GetIPInst) {
-    GetIPInst->setDeleted();
-    Variable *Dest = GetIPInst->getDest();
-    Variable *CallDest =
-        Dest->hasReg() ? Dest
-                       : getPhysicalRegister(Traits::RegisterSet::Reg_eax);
-    // Call the getIP_<reg> helper.
-    IceString RegName = Traits::getRegName(CallDest->getRegNum());
-    Constant *CallTarget = Ctx->getConstantExternSym(H_getIP_prefix + RegName);
-    Context.insert<Traits::Insts::Call>(CallDest, CallTarget);
-    // Insert a new version of InstX86GetIP.
-    Context.insert<Traits::Insts::GetIP>(CallDest);
-    // Spill the register to its home stack location if necessary.
-    if (!Dest->hasReg()) {
-      _mov(Dest, CallDest);
-    }
-  }
-
-  const VarList &Args = Func->getArgs();
-  size_t InArgsSizeBytes = 0;
-  unsigned NumXmmArgs = 0;
-  for (Variable *Arg : Args) {
-    // Skip arguments passed in registers.
-    if (isVectorType(Arg->getType()) && NumXmmArgs < Traits::X86_MAX_XMM_ARGS) {
-      ++NumXmmArgs;
-      continue;
-    }
-    // For esp-based frames where the allocas are done outside the prolog, the
-    // esp value may not stabilize to its home value until after all the
-    // fixed-size alloca instructions have executed.  In this case, a stack
-    // adjustment is needed when accessing in-args in order to copy them into
-    // registers.
-    size_t StackAdjBytes = 0;
-    if (!IsEbpBasedFrame && !PrologEmitsFixedAllocas)
-      StackAdjBytes -= FixedAllocaSizeBytes;
-    finishArgumentLowering(Arg, FramePtr, BasicFrameOffset, StackAdjBytes,
-                           InArgsSizeBytes);
-  }
-
-  // Fill in stack offsets for locals.
-  assignVarStackSlots(SortedSpilledVariables, SpillAreaPaddingBytes,
-                      SpillAreaSizeBytes, GlobalsAndSubsequentPaddingSize,
-                      IsEbpBasedFrame);
-  // Assign stack offsets to variables that have been linked to spilled
-  // variables.
-  for (Variable *Var : VariablesLinkedToSpillSlots) {
-    Variable *Linked =
-        (llvm::cast<typename Traits::SpillVariable>(Var))->getLinkedTo();
-    Var->setStackOffset(Linked->getStackOffset());
-  }
-  this->HasComputedFrame = true;
-
-  if (BuildDefs::dump() && Func->isVerbose(IceV_Frame)) {
-    OstreamLocker L(Func->getContext());
-    Ostream &Str = Func->getContext()->getStrDump();
-
-    Str << "Stack layout:\n";
-    uint32_t EspAdjustmentPaddingSize =
-        SpillAreaSizeBytes - LocalsSpillAreaSize -
-        GlobalsAndSubsequentPaddingSize - SpillAreaPaddingBytes -
-        maxOutArgsSizeBytes();
-    Str << " in-args = " << InArgsSizeBytes << " bytes\n"
-        << " return address = " << Traits::X86_RET_IP_SIZE_BYTES << " bytes\n"
-        << " preserved registers = " << PreservedRegsSizeBytes << " bytes\n"
-        << " spill area padding = " << SpillAreaPaddingBytes << " bytes\n"
-        << " globals spill area = " << GlobalsSize << " bytes\n"
-        << " globals-locals spill areas intermediate padding = "
-        << GlobalsAndSubsequentPaddingSize - GlobalsSize << " bytes\n"
-        << " locals spill area = " << LocalsSpillAreaSize << " bytes\n"
-        << " esp alignment padding = " << EspAdjustmentPaddingSize
-        << " bytes\n";
-
-    Str << "Stack details:\n"
-        << " esp adjustment = " << SpillAreaSizeBytes << " bytes\n"
-        << " spill area alignment = " << SpillAreaAlignmentBytes << " bytes\n"
-        << " outgoing args size = " << maxOutArgsSizeBytes() << " bytes\n"
-        << " locals spill area alignment = " << LocalsSlotsAlignmentBytes
-        << " bytes\n"
-        << " is ebp based = " << IsEbpBasedFrame << "\n";
-  }
-}
-
-void TargetX8632::addEpilog(CfgNode *Node) {
-  InstList &Insts = Node->getInsts();
-  InstList::reverse_iterator RI, E;
-  for (RI = Insts.rbegin(), E = Insts.rend(); RI != E; ++RI) {
-    if (llvm::isa<typename Traits::Insts::Ret>(*RI))
-      break;
-  }
-  if (RI == E)
-    return;
-
-  // Convert the reverse_iterator position into its corresponding (forward)
-  // iterator position.
-  InstList::iterator InsertPoint = RI.base();
-  --InsertPoint;
-  Context.init(Node);
-  Context.setInsertPoint(InsertPoint);
-
-  Variable *esp = getPhysicalRegister(Traits::RegisterSet::Reg_esp);
-  if (IsEbpBasedFrame) {
-    Variable *ebp = getPhysicalRegister(Traits::RegisterSet::Reg_ebp);
-    // For late-stage liveness analysis (e.g. asm-verbose mode), adding a fake
-    // use of esp before the assignment of esp=ebp keeps previous esp
-    // adjustments from being dead-code eliminated.
-    Context.insert<InstFakeUse>(esp);
-    _mov(esp, ebp);
-    _pop(ebp);
-  } else {
-    // add esp, SpillAreaSizeBytes
-    if (SpillAreaSizeBytes)
-      _add(esp, Ctx->getConstantInt32(SpillAreaSizeBytes));
-  }
-
-  // Add pop instructions for preserved registers.
-  llvm::SmallBitVector CalleeSaves =
-      getRegisterSet(RegSet_CalleeSave, RegSet_None);
-  llvm::SmallBitVector Popped(CalleeSaves.size());
-  for (SizeT i = 0; i < CalleeSaves.size(); ++i) {
-    SizeT Canonical = Traits::getBaseReg(i);
-    if (CalleeSaves[i] && RegsUsed[i]) {
-      Popped[Canonical] = true;
-    }
-  }
-  for (SizeT i = 0; i < Popped.size(); ++i) {
-    SizeT j = Popped.size() - i - 1;
-    SizeT Canonical = Traits::getBaseReg(j);
-    if (j == Traits::RegisterSet::Reg_ebp && IsEbpBasedFrame)
-      continue;
-    if (Popped[j]) {
-      _pop(getPhysicalRegister(Canonical));
-    }
-  }
-
-  if (!NeedSandboxing) {
-    return;
-  }
-
+void TargetX8632::emitSandboxedReturn() {
   // Change the original ret instruction into a sandboxed return sequence.
   // t:ecx = pop
   // bundle_lock
@@ -551,11 +267,6 @@ void TargetX8632::addEpilog(CfgNode *Node) {
   Variable *T_ecx = makeReg(IceType_i32, Traits::RegisterSet::Reg_ecx);
   _pop(T_ecx);
   lowerIndirectJump(T_ecx);
-  if (RI->getSrcSize()) {
-    auto *RetValue = llvm::cast<Variable>(RI->getSrc(0));
-    Context.insert<InstFakeUse>(RetValue);
-  }
-  RI->setDeleted();
 }
 
 void TargetX8632::emitJumpTable(const Cfg *Func,
index 39ba608..5b2d6b0 100644 (file)
@@ -55,13 +55,16 @@ protected:
     llvm::report_fatal_error("sandbox mem reference for x86-32.");
   }
   void _sub_sp(Operand *Adjustment);
+  void _link_bp();
+  void _unlink_bp();
+  void _push_reg(Variable *Reg);
 
   void initSandbox() {}
+  void emitSandboxedReturn();
   void lowerIndirectJump(Variable *JumpTarget);
+  void emitGetIP(CfgNode *Node);
   Inst *emitCallToTarget(Operand *CallTarget, Variable *ReturnReg) override;
   Variable *moveReturnValueToRegister(Operand *Value, Type ReturnType) override;
-  void addProlog(CfgNode *Node) override;
-  void addEpilog(CfgNode *Node) override;
 
 private:
   ENABLE_MAKE_UNIQUE;
index 6fe92bf..c023949 100644 (file)
@@ -215,6 +215,84 @@ void TargetX8664::_push_rbp() {
   Context.insert<typename Traits::Insts::Store>(ebp, TopOfStack);
 }
 
+void TargetX8664::_link_bp() {
+  Variable *esp =
+      getPhysicalRegister(Traits::RegisterSet::Reg_esp, IceType_i32);
+  Variable *rsp =
+      getPhysicalRegister(Traits::RegisterSet::Reg_rsp, Traits::WordType);
+  Variable *ebp =
+      getPhysicalRegister(Traits::RegisterSet::Reg_ebp, IceType_i32);
+  Variable *rbp =
+      getPhysicalRegister(Traits::RegisterSet::Reg_rbp, Traits::WordType);
+  Variable *r15 =
+      getPhysicalRegister(Traits::RegisterSet::Reg_r15, Traits::WordType);
+
+  if (!NeedSandboxing) {
+    _push(rbp);
+    _mov(rbp, rsp);
+  } else {
+    _push_rbp();
+
+    AutoBundle _(this);
+    _redefined(Context.insert<InstFakeDef>(ebp, rbp));
+    _redefined(Context.insert<InstFakeDef>(esp, rsp));
+    _mov(ebp, esp);
+    _redefined(Context.insert<InstFakeDef>(rsp, esp));
+    _add(rbp, r15);
+  }
+  // Keep ebp live for late-stage liveness analysis (e.g. asm-verbose mode).
+  Context.insert<InstFakeUse>(rbp);
+}
+
+void TargetX8664::_unlink_bp() {
+  Variable *rsp =
+      getPhysicalRegister(Traits::RegisterSet::Reg_rsp, IceType_i64);
+  Variable *rbp =
+      getPhysicalRegister(Traits::RegisterSet::Reg_rbp, IceType_i64);
+  Variable *ebp =
+      getPhysicalRegister(Traits::RegisterSet::Reg_ebp, IceType_i32);
+  // For late-stage liveness analysis (e.g. asm-verbose mode), adding a fake
+  // use of rsp before the assignment of rsp=rbp keeps previous rsp
+  // adjustments from being dead-code eliminated.
+  Context.insert<InstFakeUse>(rsp);
+  if (!NeedSandboxing) {
+    _mov(rsp, rbp);
+    _pop(rbp);
+  } else {
+    _mov_sp(ebp);
+
+    Variable *r15 =
+        getPhysicalRegister(Traits::RegisterSet::Reg_r15, IceType_i64);
+    Variable *rcx =
+        getPhysicalRegister(Traits::RegisterSet::Reg_rcx, IceType_i64);
+    Variable *ecx =
+        getPhysicalRegister(Traits::RegisterSet::Reg_ecx, IceType_i32);
+
+    _pop(rcx);
+    Context.insert<InstFakeDef>(ecx, rcx);
+    AutoBundle _(this);
+    _mov(ebp, ecx);
+
+    _redefined(Context.insert<InstFakeDef>(rbp, ebp));
+    _add(rbp, r15);
+  }
+}
+
+void TargetX8664::_push_reg(Variable *Reg) {
+  Variable *rbp =
+      getPhysicalRegister(Traits::RegisterSet::Reg_rbp, Traits::WordType);
+  if (Reg != rbp || !NeedSandboxing) {
+    _push(Reg);
+  } else {
+    _push_rbp();
+  }
+}
+
+void TargetX8664::emitGetIP(CfgNode *Node) {
+  // No IP base register is needed on X86-64.
+  (void)Node;
+}
+
 Traits::X86OperandMem *TargetX8664::_sandbox_mem_reference(X86OperandMem *Mem) {
   // In x86_64-nacl, all memory references are relative to %r15 (i.e., %rzp.)
   // NaCl sandboxing also requires that any registers that are not %rsp and
@@ -326,7 +404,7 @@ Traits::X86OperandMem *TargetX8664::_sandbox_mem_reference(X86OperandMem *Mem) {
 
 void TargetX8664::_sub_sp(Operand *Adjustment) {
   Variable *rsp =
-      getPhysicalRegister(Traits::RegisterSet::Reg_rsp, IceType_i64);
+      getPhysicalRegister(Traits::RegisterSet::Reg_rsp, Traits::WordType);
   if (!NeedSandboxing) {
     _sub(rsp, Adjustment);
     return;
@@ -448,371 +526,11 @@ Variable *TargetX8664::moveReturnValueToRegister(Operand *Value,
   }
 }
 
-void TargetX8664::addProlog(CfgNode *Node) {
-  // Stack frame layout:
-  //
-  // +------------------------+
-  // | 1. return address      |
-  // +------------------------+
-  // | 2. preserved registers |
-  // +------------------------+
-  // | 3. padding             |
-  // +------------------------+
-  // | 4. global spill area   |
-  // +------------------------+
-  // | 5. padding             |
-  // +------------------------+
-  // | 6. local spill area    |
-  // +------------------------+
-  // | 7. padding             |
-  // +------------------------+
-  // | 8. allocas             |
-  // +------------------------+
-  // | 9. padding             |
-  // +------------------------+
-  // | 10. out args           |
-  // +------------------------+ <--- StackPointer
-  //
-  // The following variables record the size in bytes of the given areas:
-  //  * X86_RET_IP_SIZE_BYTES:  area 1
-  //  * PreservedRegsSizeBytes: area 2
-  //  * SpillAreaPaddingBytes:  area 3
-  //  * GlobalsSize:            area 4
-  //  * GlobalsAndSubsequentPaddingSize: areas 4 - 5
-  //  * LocalsSpillAreaSize:    area 6
-  //  * SpillAreaSizeBytes:     areas 3 - 10
-  //  * maxOutArgsSizeBytes():  area 10
-
-  // Determine stack frame offsets for each Variable without a register
-  // assignment. This can be done as one variable per stack slot. Or, do
-  // coalescing by running the register allocator again with an infinite set of
-  // registers (as a side effect, this gives variables a second chance at
-  // physical register assignment).
-  //
-  // A middle ground approach is to leverage sparsity and allocate one block of
-  // space on the frame for globals (variables with multi-block lifetime), and
-  // one block to share for locals (single-block lifetime).
-
-  Context.init(Node);
-  Context.setInsertPoint(Context.getCur());
-
-  llvm::SmallBitVector CalleeSaves =
-      getRegisterSet(RegSet_CalleeSave, RegSet_None);
-  RegsUsed = llvm::SmallBitVector(CalleeSaves.size());
-  VarList SortedSpilledVariables, VariablesLinkedToSpillSlots;
-  size_t GlobalsSize = 0;
-  // If there is a separate locals area, this represents that area. Otherwise
-  // it counts any variable not counted by GlobalsSize.
-  SpillAreaSizeBytes = 0;
-  // If there is a separate locals area, this specifies the alignment for it.
-  uint32_t LocalsSlotsAlignmentBytes = 0;
-  // The entire spill locations area gets aligned to largest natural alignment
-  // of the variables that have a spill slot.
-  uint32_t SpillAreaAlignmentBytes = 0;
-  // A spill slot linked to a variable with a stack slot should reuse that
-  // stack slot.
-  std::function<bool(Variable *)> TargetVarHook =
-      [&VariablesLinkedToSpillSlots](Variable *Var) {
-        if (auto *SpillVar =
-                llvm::dyn_cast<typename Traits::SpillVariable>(Var)) {
-          assert(Var->mustNotHaveReg());
-          if (SpillVar->getLinkedTo() && !SpillVar->getLinkedTo()->hasReg()) {
-            VariablesLinkedToSpillSlots.push_back(Var);
-            return true;
-          }
-        }
-        return false;
-      };
-
-  // Compute the list of spilled variables and bounds for GlobalsSize, etc.
-  getVarStackSlotParams(SortedSpilledVariables, RegsUsed, &GlobalsSize,
-                        &SpillAreaSizeBytes, &SpillAreaAlignmentBytes,
-                        &LocalsSlotsAlignmentBytes, TargetVarHook);
-  uint32_t LocalsSpillAreaSize = SpillAreaSizeBytes;
-  SpillAreaSizeBytes += GlobalsSize;
-
-  // Add push instructions for preserved registers.
-  uint32_t NumCallee = 0;
-  size_t PreservedRegsSizeBytes = 0;
-  llvm::SmallBitVector Pushed(CalleeSaves.size());
-  for (SizeT i = 0; i < CalleeSaves.size(); ++i) {
-    const int32_t Canonical = Traits::getBaseReg(i);
-    assert(Canonical == Traits::getBaseReg(Canonical));
-    if (CalleeSaves[i] && RegsUsed[i])
-      Pushed[Canonical] = true;
-  }
-
-  Variable *rbp =
-      getPhysicalRegister(Traits::RegisterSet::Reg_rbp, IceType_i64);
-  Variable *ebp =
-      getPhysicalRegister(Traits::RegisterSet::Reg_ebp, IceType_i32);
-  Variable *rsp =
-      getPhysicalRegister(Traits::RegisterSet::Reg_rsp, IceType_i64);
-
-  for (SizeT i = 0; i < Pushed.size(); ++i) {
-    if (!Pushed[i])
-      continue;
-    assert(static_cast<int32_t>(i) == Traits::getBaseReg(i));
-    ++NumCallee;
-    PreservedRegsSizeBytes += typeWidthInBytes(IceType_i64);
-    Variable *Src = getPhysicalRegister(i, IceType_i64);
-    if (Src != rbp || !NeedSandboxing) {
-      _push(getPhysicalRegister(i, IceType_i64));
-    } else {
-      _push_rbp();
-    }
-  }
-  Ctx->statsUpdateRegistersSaved(NumCallee);
-
-  // Generate "push ebp; mov ebp, esp"
-  if (IsEbpBasedFrame) {
-    assert((RegsUsed & getRegisterSet(RegSet_FramePointer, RegSet_None))
-               .count() == 0);
-    PreservedRegsSizeBytes += typeWidthInBytes(IceType_i64);
-    Variable *esp =
-        getPhysicalRegister(Traits::RegisterSet::Reg_esp, IceType_i32);
-    Variable *r15 =
-        getPhysicalRegister(Traits::RegisterSet::Reg_r15, IceType_i64);
-
-    if (!NeedSandboxing) {
-      _push(rbp);
-      _mov(rbp, rsp);
-    } else {
-      _push_rbp();
-
-      AutoBundle _(this);
-      _redefined(Context.insert<InstFakeDef>(ebp, rbp));
-      _redefined(Context.insert<InstFakeDef>(esp, rsp));
-      _mov(ebp, esp);
-      _redefined(Context.insert<InstFakeDef>(rsp, esp));
-      _add(rbp, r15);
-    }
-    // Keep ebp live for late-stage liveness analysis (e.g. asm-verbose mode).
-    Context.insert<InstFakeUse>(rbp);
-  }
-
-  // Align the variables area. SpillAreaPaddingBytes is the size of the region
-  // after the preserved registers and before the spill areas.
-  // LocalsSlotsPaddingBytes is the amount of padding between the globals and
-  // locals area if they are separate.
-  assert(SpillAreaAlignmentBytes <= Traits::X86_STACK_ALIGNMENT_BYTES);
-  assert(LocalsSlotsAlignmentBytes <= SpillAreaAlignmentBytes);
-  uint32_t SpillAreaPaddingBytes = 0;
-  uint32_t LocalsSlotsPaddingBytes = 0;
-  alignStackSpillAreas(Traits::X86_RET_IP_SIZE_BYTES + PreservedRegsSizeBytes,
-                       SpillAreaAlignmentBytes, GlobalsSize,
-                       LocalsSlotsAlignmentBytes, &SpillAreaPaddingBytes,
-                       &LocalsSlotsPaddingBytes);
-  SpillAreaSizeBytes += SpillAreaPaddingBytes + LocalsSlotsPaddingBytes;
-  uint32_t GlobalsAndSubsequentPaddingSize =
-      GlobalsSize + LocalsSlotsPaddingBytes;
-
-  // Align esp if necessary.
-  if (NeedsStackAlignment) {
-    uint32_t StackOffset =
-        Traits::X86_RET_IP_SIZE_BYTES + PreservedRegsSizeBytes;
-    uint32_t StackSize =
-        Traits::applyStackAlignment(StackOffset + SpillAreaSizeBytes);
-    StackSize = Traits::applyStackAlignment(StackSize + maxOutArgsSizeBytes());
-    SpillAreaSizeBytes = StackSize - StackOffset;
-  } else {
-    SpillAreaSizeBytes += maxOutArgsSizeBytes();
-  }
-
-  // Combine fixed allocations into SpillAreaSizeBytes if we are emitting the
-  // fixed allocations in the prolog.
-  if (PrologEmitsFixedAllocas)
-    SpillAreaSizeBytes += FixedAllocaSizeBytes;
-  // Generate "sub esp, SpillAreaSizeBytes"
-  if (SpillAreaSizeBytes) {
-    if (NeedSandboxing) {
-      _sub_sp(Ctx->getConstantInt32(SpillAreaSizeBytes));
-    } else {
-      _sub(getPhysicalRegister(getStackReg(), IceType_i64),
-           Ctx->getConstantInt32(SpillAreaSizeBytes));
-    }
-    // If the fixed allocas are aligned more than the stack frame, align the
-    // stack pointer accordingly.
-    if (PrologEmitsFixedAllocas &&
-        FixedAllocaAlignBytes > Traits::X86_STACK_ALIGNMENT_BYTES) {
-      assert(IsEbpBasedFrame);
-      _and(getPhysicalRegister(Traits::RegisterSet::Reg_rsp, IceType_i64),
-           Ctx->getConstantInt32(-FixedAllocaAlignBytes));
-    }
-  }
-
-  // Account for alloca instructions with known frame offsets.
-  if (!PrologEmitsFixedAllocas)
-    SpillAreaSizeBytes += FixedAllocaSizeBytes;
-
-  Ctx->statsUpdateFrameBytes(SpillAreaSizeBytes);
-
-  // Fill in stack offsets for stack args, and copy args into registers for
-  // those that were register-allocated. Args are pushed right to left, so
-  // Arg[0] is closest to the stack/frame pointer.
-  Variable *FramePtr =
-      getPhysicalRegister(getFrameOrStackReg(), Traits::WordType);
-  size_t BasicFrameOffset =
-      PreservedRegsSizeBytes + Traits::X86_RET_IP_SIZE_BYTES;
-  if (!IsEbpBasedFrame)
-    BasicFrameOffset += SpillAreaSizeBytes;
-
-  const VarList &Args = Func->getArgs();
-  size_t InArgsSizeBytes = 0;
-  unsigned NumXmmArgs = 0;
-  unsigned NumGPRArgs = 0;
-  for (Variable *Arg : Args) {
-    // Skip arguments passed in registers.
-    if (isVectorType(Arg->getType()) || isScalarFloatingType(Arg->getType())) {
-      if (NumXmmArgs < Traits::X86_MAX_XMM_ARGS) {
-        ++NumXmmArgs;
-        continue;
-      }
-    } else {
-      assert(isScalarIntegerType(Arg->getType()));
-      if (NumGPRArgs < Traits::X86_MAX_GPR_ARGS) {
-        ++NumGPRArgs;
-        continue;
-      }
-    }
-    // For esp-based frames, the esp value may not stabilize to its home value
-    // until after all the fixed-size alloca instructions have executed.  In
-    // this case, a stack adjustment is needed when accessing in-args in order
-    // to copy them into registers.
-    size_t StackAdjBytes = 0;
-    if (!IsEbpBasedFrame && !PrologEmitsFixedAllocas)
-      StackAdjBytes -= FixedAllocaSizeBytes;
-    finishArgumentLowering(Arg, FramePtr, BasicFrameOffset, StackAdjBytes,
-                           InArgsSizeBytes);
-  }
-
-  // Fill in stack offsets for locals.
-  assignVarStackSlots(SortedSpilledVariables, SpillAreaPaddingBytes,
-                      SpillAreaSizeBytes, GlobalsAndSubsequentPaddingSize,
-                      IsEbpBasedFrame);
-  // Assign stack offsets to variables that have been linked to spilled
-  // variables.
-  for (Variable *Var : VariablesLinkedToSpillSlots) {
-    Variable *Linked =
-        (llvm::cast<typename Traits::SpillVariable>(Var))->getLinkedTo();
-    Var->setStackOffset(Linked->getStackOffset());
-  }
-  this->HasComputedFrame = true;
-
-  if (BuildDefs::dump() && Func->isVerbose(IceV_Frame)) {
-    OstreamLocker L(Func->getContext());
-    Ostream &Str = Func->getContext()->getStrDump();
-
-    Str << "Stack layout:\n";
-    uint32_t EspAdjustmentPaddingSize =
-        SpillAreaSizeBytes - LocalsSpillAreaSize -
-        GlobalsAndSubsequentPaddingSize - SpillAreaPaddingBytes -
-        maxOutArgsSizeBytes();
-    Str << " in-args = " << InArgsSizeBytes << " bytes\n"
-        << " return address = " << Traits::X86_RET_IP_SIZE_BYTES << " bytes\n"
-        << " preserved registers = " << PreservedRegsSizeBytes << " bytes\n"
-        << " spill area padding = " << SpillAreaPaddingBytes << " bytes\n"
-        << " globals spill area = " << GlobalsSize << " bytes\n"
-        << " globals-locals spill areas intermediate padding = "
-        << GlobalsAndSubsequentPaddingSize - GlobalsSize << " bytes\n"
-        << " locals spill area = " << LocalsSpillAreaSize << " bytes\n"
-        << " esp alignment padding = " << EspAdjustmentPaddingSize
-        << " bytes\n";
-
-    Str << "Stack details:\n"
-        << " esp adjustment = " << SpillAreaSizeBytes << " bytes\n"
-        << " spill area alignment = " << SpillAreaAlignmentBytes << " bytes\n"
-        << " outgoing args size = " << maxOutArgsSizeBytes() << " bytes\n"
-        << " locals spill area alignment = " << LocalsSlotsAlignmentBytes
-        << " bytes\n"
-        << " is ebp based = " << IsEbpBasedFrame << "\n";
-  }
-}
-
-void TargetX8664::addEpilog(CfgNode *Node) {
-  InstList &Insts = Node->getInsts();
-  InstList::reverse_iterator RI, E;
-  for (RI = Insts.rbegin(), E = Insts.rend(); RI != E; ++RI) {
-    if (llvm::isa<typename Traits::Insts::Ret>(*RI))
-      break;
-  }
-  if (RI == E)
-    return;
-
-  // Convert the reverse_iterator position into its corresponding (forward)
-  // iterator position.
-  InstList::iterator InsertPoint = RI.base();
-  --InsertPoint;
-  Context.init(Node);
-  Context.setInsertPoint(InsertPoint);
-
-  Variable *rsp =
-      getPhysicalRegister(Traits::RegisterSet::Reg_rsp, IceType_i64);
-
-  if (!IsEbpBasedFrame) {
-    // add rsp, SpillAreaSizeBytes
-    if (SpillAreaSizeBytes != 0) {
-      _add_sp(Ctx->getConstantInt32(SpillAreaSizeBytes));
-    }
-  } else {
-    Variable *rbp =
-        getPhysicalRegister(Traits::RegisterSet::Reg_rbp, IceType_i64);
-    Variable *ebp =
-        getPhysicalRegister(Traits::RegisterSet::Reg_ebp, IceType_i32);
-    // For late-stage liveness analysis (e.g. asm-verbose mode), adding a fake
-    // use of rsp before the assignment of rsp=rbp keeps previous rsp
-    // adjustments from being dead-code eliminated.
-    Context.insert<InstFakeUse>(rsp);
-    if (!NeedSandboxing) {
-      _mov(rsp, rbp);
-      _pop(rbp);
-    } else {
-      _mov_sp(ebp);
-
-      Variable *r15 =
-          getPhysicalRegister(Traits::RegisterSet::Reg_r15, IceType_i64);
-      Variable *rcx =
-          getPhysicalRegister(Traits::RegisterSet::Reg_rcx, IceType_i64);
-      Variable *ecx =
-          getPhysicalRegister(Traits::RegisterSet::Reg_ecx, IceType_i32);
-
-      _pop(rcx);
-      Context.insert<InstFakeDef>(ecx, rcx);
-      AutoBundle _(this);
-      _mov(ebp, ecx);
-
-      _redefined(Context.insert<InstFakeDef>(rbp, ebp));
-      _add(rbp, r15);
-    }
-  }
-
-  // Add pop instructions for preserved registers.
-  llvm::SmallBitVector CalleeSaves =
-      getRegisterSet(RegSet_CalleeSave, RegSet_None);
-  llvm::SmallBitVector Popped(CalleeSaves.size());
-  for (int32_t i = CalleeSaves.size() - 1; i >= 0; --i) {
-    if (i == Traits::RegisterSet::Reg_rbp && IsEbpBasedFrame)
-      continue;
-    const SizeT Canonical = Traits::getBaseReg(i);
-    if (CalleeSaves[i] && RegsUsed[i])
-      Popped[Canonical] = true;
-  }
-  for (int32_t i = Popped.size() - 1; i >= 0; --i) {
-    if (!Popped[i])
-      continue;
-    assert(i == Traits::getBaseReg(i));
-    _pop(getPhysicalRegister(i, IceType_i64));
-  }
-
-  if (!NeedSandboxing) {
-    return;
-  }
-
+void TargetX8664::emitSandboxedReturn() {
   Variable *T_rcx = makeReg(IceType_i64, Traits::RegisterSet::Reg_rcx);
   Variable *T_ecx = makeReg(IceType_i32, Traits::RegisterSet::Reg_ecx);
   _pop(T_rcx);
   _mov(T_ecx, T_rcx);
-
   // lowerIndirectJump(T_ecx);
   Variable *r15 =
       getPhysicalRegister(Traits::RegisterSet::Reg_r15, IceType_i64);
@@ -827,12 +545,6 @@ void TargetX8664::addEpilog(CfgNode *Node) {
 
     _jmp(T_rcx);
   }
-
-  if (RI->getSrcSize()) {
-    auto *RetValue = llvm::cast<Variable>(RI->getSrc(0));
-    Context.insert<InstFakeUse>(RetValue);
-  }
-  RI->setDeleted();
 }
 
 void TargetX8664::emitJumpTable(const Cfg *Func,
index e10d834..0a3cdef 100644 (file)
@@ -57,13 +57,16 @@ protected:
   void _push_rbp();
   Traits::X86OperandMem *_sandbox_mem_reference(X86OperandMem *Mem);
   void _sub_sp(Operand *Adjustment);
+  void _link_bp();
+  void _unlink_bp();
+  void _push_reg(Variable *Reg);
 
   void initSandbox();
+  void emitSandboxedReturn();
   void lowerIndirectJump(Variable *JumpTarget);
+  void emitGetIP(CfgNode *Node);
   Inst *emitCallToTarget(Operand *CallTarget, Variable *ReturnReg) override;
   Variable *moveReturnValueToRegister(Operand *Value, Type ReturnType) override;
-  void addProlog(CfgNode *Node) override;
-  void addEpilog(CfgNode *Node) override;
 
 private:
   ENABLE_MAKE_UNIQUE;
index 72e4f20..2a4a728 100644 (file)
@@ -177,9 +177,11 @@ public:
         "Hey, yo! This is x86-64. Watcha doin'? (hiOperand)");
   }
 
+  void addProlog(CfgNode *Node) override;
   void finishArgumentLowering(Variable *Arg, Variable *FramePtr,
                               size_t BasicFrameOffset, size_t StackAdjBytes,
                               size_t &InArgsSizeBytes);
+  void addEpilog(CfgNode *Node) override;
   X86Address stackVarToAsmOperand(const Variable *Var) const;
 
   InstructionSetEnum getInstructionSet() const { return InstructionSet; }
@@ -282,6 +284,13 @@ protected:
   void scalarizeArithmetic(InstArithmetic::OpKind K, Variable *Dest,
                            Operand *Src0, Operand *Src1);
 
+  void emitGetIP(CfgNode *Node) {
+    dispatchToConcrete(&Traits::ConcreteTarget::emitGetIP, std::move(Node));
+  }
+  /// Emit a sandboxed return sequence rather than a return.
+  void emitSandboxedReturn() {
+    dispatchToConcrete(&Traits::ConcreteTarget::emitSandboxedReturn);
+  }
   /// Emit just the call instruction (without argument or return variable
   /// processing), sandboxing if needed.
   virtual Inst *emitCallToTarget(Operand *CallTarget, Variable *ReturnReg) = 0;
@@ -588,6 +597,10 @@ protected:
   void _lea(Variable *Dest, Operand *Src0) {
     Context.insert<typename Traits::Insts::Lea>(Dest, Src0);
   }
+  void _link_bp() { dispatchToConcrete(&Traits::ConcreteTarget::_link_bp); }
+  void _push_reg(Variable *Reg) {
+    dispatchToConcrete(&Traits::ConcreteTarget::_push_reg, std::move(Reg));
+  }
   void _mfence() { Context.insert<typename Traits::Insts::Mfence>(); }
   /// Moves can be used to redefine registers, creating "partial kills" for
   /// liveness.  Mark where moves are used in this way.
@@ -836,6 +849,7 @@ protected:
     Context.insert<typename Traits::Insts::Ucomiss>(Src0, Src1);
   }
   void _ud2() { Context.insert<typename Traits::Insts::UD2>(); }
+  void _unlink_bp() { dispatchToConcrete(&Traits::ConcreteTarget::_unlink_bp); }
   void _xadd(Operand *Dest, Variable *Src, bool Locked) {
     AutoMemorySandboxer<> _(this, &Dest, &Src);
     Context.insert<typename Traits::Insts::Xadd>(Dest, Src, Locked);
index 2669fcf..e70c757 100644 (file)
@@ -874,6 +874,277 @@ TargetX86Base<TraitsType>::stackVarToAsmOperand(const Variable *Var) const {
                     AssemblerFixup::NoFixup);
 }
 
+template <typename TraitsType>
+void TargetX86Base<TraitsType>::addProlog(CfgNode *Node) {
+  // Stack frame layout:
+  //
+  // +------------------------+
+  // | 1. return address      |
+  // +------------------------+
+  // | 2. preserved registers |
+  // +------------------------+
+  // | 3. padding             |
+  // +------------------------+
+  // | 4. global spill area   |
+  // +------------------------+
+  // | 5. padding             |
+  // +------------------------+
+  // | 6. local spill area    |
+  // +------------------------+
+  // | 7. padding             |
+  // +------------------------+
+  // | 8. allocas             |
+  // +------------------------+
+  // | 9. padding             |
+  // +------------------------+
+  // | 10. out args           |
+  // +------------------------+ <--- StackPointer
+  //
+  // The following variables record the size in bytes of the given areas:
+  //  * X86_RET_IP_SIZE_BYTES:  area 1
+  //  * PreservedRegsSizeBytes: area 2
+  //  * SpillAreaPaddingBytes:  area 3
+  //  * GlobalsSize:            area 4
+  //  * GlobalsAndSubsequentPaddingSize: areas 4 - 5
+  //  * LocalsSpillAreaSize:    area 6
+  //  * SpillAreaSizeBytes:     areas 3 - 10
+  //  * maxOutArgsSizeBytes():  area 10
+
+  // Determine stack frame offsets for each Variable without a register
+  // assignment. This can be done as one variable per stack slot. Or, do
+  // coalescing by running the register allocator again with an infinite set of
+  // registers (as a side effect, this gives variables a second chance at
+  // physical register assignment).
+  //
+  // A middle ground approach is to leverage sparsity and allocate one block of
+  // space on the frame for globals (variables with multi-block lifetime), and
+  // one block to share for locals (single-block lifetime).
+
+  Context.init(Node);
+  Context.setInsertPoint(Context.getCur());
+
+  llvm::SmallBitVector CalleeSaves =
+      getRegisterSet(RegSet_CalleeSave, RegSet_None);
+  RegsUsed = llvm::SmallBitVector(CalleeSaves.size());
+  VarList SortedSpilledVariables, VariablesLinkedToSpillSlots;
+  size_t GlobalsSize = 0;
+  // If there is a separate locals area, this represents that area. Otherwise
+  // it counts any variable not counted by GlobalsSize.
+  SpillAreaSizeBytes = 0;
+  // If there is a separate locals area, this specifies the alignment for it.
+  uint32_t LocalsSlotsAlignmentBytes = 0;
+  // The entire spill locations area gets aligned to largest natural alignment
+  // of the variables that have a spill slot.
+  uint32_t SpillAreaAlignmentBytes = 0;
+  // A spill slot linked to a variable with a stack slot should reuse that
+  // stack slot.
+  std::function<bool(Variable *)> TargetVarHook =
+      [&VariablesLinkedToSpillSlots](Variable *Var) {
+        if (auto *SpillVar =
+                llvm::dyn_cast<typename Traits::SpillVariable>(Var)) {
+          assert(Var->mustNotHaveReg());
+          if (SpillVar->getLinkedTo() && !SpillVar->getLinkedTo()->hasReg()) {
+            VariablesLinkedToSpillSlots.push_back(Var);
+            return true;
+          }
+        }
+        return false;
+      };
+
+  // Compute the list of spilled variables and bounds for GlobalsSize, etc.
+  getVarStackSlotParams(SortedSpilledVariables, RegsUsed, &GlobalsSize,
+                        &SpillAreaSizeBytes, &SpillAreaAlignmentBytes,
+                        &LocalsSlotsAlignmentBytes, TargetVarHook);
+  uint32_t LocalsSpillAreaSize = SpillAreaSizeBytes;
+  SpillAreaSizeBytes += GlobalsSize;
+
+  // Add push instructions for preserved registers.
+  uint32_t NumCallee = 0;
+  size_t PreservedRegsSizeBytes = 0;
+  llvm::SmallBitVector Pushed(CalleeSaves.size());
+  for (SizeT i = 0; i < CalleeSaves.size(); ++i) {
+    const int32_t Canonical = Traits::getBaseReg(i);
+    assert(Canonical == Traits::getBaseReg(Canonical));
+    if (CalleeSaves[i] && RegsUsed[i]) {
+      Pushed[Canonical] = true;
+    }
+  }
+  for (SizeT i = 0; i < Pushed.size(); ++i) {
+    if (!Pushed[i])
+      continue;
+    assert(static_cast<int32_t>(i) == Traits::getBaseReg(i));
+    ++NumCallee;
+    PreservedRegsSizeBytes += typeWidthInBytes(Traits::WordType);
+    _push_reg(getPhysicalRegister(i, Traits::WordType));
+  }
+  Ctx->statsUpdateRegistersSaved(NumCallee);
+
+  // Generate "push frameptr; mov frameptr, stackptr"
+  if (IsEbpBasedFrame) {
+    assert((RegsUsed & getRegisterSet(RegSet_FramePointer, RegSet_None))
+               .count() == 0);
+    PreservedRegsSizeBytes += typeWidthInBytes(Traits::WordType);
+    _link_bp();
+  }
+
+  // Align the variables area. SpillAreaPaddingBytes is the size of the region
+  // after the preserved registers and before the spill areas.
+  // LocalsSlotsPaddingBytes is the amount of padding between the globals and
+  // locals area if they are separate.
+  assert(SpillAreaAlignmentBytes <= Traits::X86_STACK_ALIGNMENT_BYTES);
+  assert(LocalsSlotsAlignmentBytes <= SpillAreaAlignmentBytes);
+  uint32_t SpillAreaPaddingBytes = 0;
+  uint32_t LocalsSlotsPaddingBytes = 0;
+  alignStackSpillAreas(Traits::X86_RET_IP_SIZE_BYTES + PreservedRegsSizeBytes,
+                       SpillAreaAlignmentBytes, GlobalsSize,
+                       LocalsSlotsAlignmentBytes, &SpillAreaPaddingBytes,
+                       &LocalsSlotsPaddingBytes);
+  SpillAreaSizeBytes += SpillAreaPaddingBytes + LocalsSlotsPaddingBytes;
+  uint32_t GlobalsAndSubsequentPaddingSize =
+      GlobalsSize + LocalsSlotsPaddingBytes;
+
+  // Functions returning scalar floating point types may need to convert values
+  // from an in-register xmm value to the top of the x87 floating point stack.
+  // This is done by a movp[sd] and an fld[sd].  Ensure there is enough scratch
+  // space on the stack for this.
+  const Type ReturnType = Func->getReturnType();
+  if (!Traits::X86_PASS_SCALAR_FP_IN_XMM) {
+    if (isScalarFloatingType(ReturnType)) {
+      // Avoid misaligned double-precicion load/store.
+      NeedsStackAlignment = true;
+      SpillAreaSizeBytes =
+          std::max(typeWidthInBytesOnStack(ReturnType), SpillAreaSizeBytes);
+    }
+  }
+
+  // Align esp if necessary.
+  if (NeedsStackAlignment) {
+    uint32_t StackOffset =
+        Traits::X86_RET_IP_SIZE_BYTES + PreservedRegsSizeBytes;
+    uint32_t StackSize =
+        Traits::applyStackAlignment(StackOffset + SpillAreaSizeBytes);
+    StackSize = Traits::applyStackAlignment(StackSize + maxOutArgsSizeBytes());
+    SpillAreaSizeBytes = StackSize - StackOffset;
+  } else {
+    SpillAreaSizeBytes += maxOutArgsSizeBytes();
+  }
+
+  // Combine fixed allocations into SpillAreaSizeBytes if we are emitting the
+  // fixed allocations in the prolog.
+  if (PrologEmitsFixedAllocas)
+    SpillAreaSizeBytes += FixedAllocaSizeBytes;
+  if (SpillAreaSizeBytes) {
+    // Generate "sub stackptr, SpillAreaSizeBytes"
+    _sub_sp(Ctx->getConstantInt32(SpillAreaSizeBytes));
+    // If the fixed allocas are aligned more than the stack frame, align the
+    // stack pointer accordingly.
+    if (PrologEmitsFixedAllocas &&
+        FixedAllocaAlignBytes > Traits::X86_STACK_ALIGNMENT_BYTES) {
+      assert(IsEbpBasedFrame);
+      _and(getPhysicalRegister(getStackReg(), Traits::WordType),
+           Ctx->getConstantInt32(-FixedAllocaAlignBytes));
+    }
+  }
+
+  // Account for known-frame-offset alloca instructions that were not already
+  // combined into the prolog.
+  if (!PrologEmitsFixedAllocas)
+    SpillAreaSizeBytes += FixedAllocaSizeBytes;
+
+  Ctx->statsUpdateFrameBytes(SpillAreaSizeBytes);
+
+  // Fill in stack offsets for stack args, and copy args into registers for
+  // those that were register-allocated. Args are pushed right to left, so
+  // Arg[0] is closest to the stack/frame pointer.
+  Variable *FramePtr =
+      getPhysicalRegister(getFrameOrStackReg(), Traits::WordType);
+  size_t BasicFrameOffset =
+      PreservedRegsSizeBytes + Traits::X86_RET_IP_SIZE_BYTES;
+  if (!IsEbpBasedFrame)
+    BasicFrameOffset += SpillAreaSizeBytes;
+
+  emitGetIP(Node);
+
+  const VarList &Args = Func->getArgs();
+  size_t InArgsSizeBytes = 0;
+  unsigned NumXmmArgs = 0;
+  unsigned NumGPRArgs = 0;
+  for (Variable *Arg : Args) {
+    // Skip arguments passed in registers.
+    if (isVectorType(Arg->getType())) {
+      if (Traits::getRegisterForXmmArgNum(NumXmmArgs) != Variable::NoRegister) {
+        ++NumXmmArgs;
+        continue;
+      }
+    } else if (isScalarFloatingType(Arg->getType())) {
+      if (Traits::X86_PASS_SCALAR_FP_IN_XMM &&
+          Traits::getRegisterForXmmArgNum(NumXmmArgs) != Variable::NoRegister) {
+        ++NumXmmArgs;
+        continue;
+      }
+    } else {
+      assert(isScalarIntegerType(Arg->getType()));
+      if (Traits::getRegisterForGprArgNum(Traits::WordType, NumGPRArgs) !=
+          Variable::NoRegister) {
+        ++NumGPRArgs;
+        continue;
+      }
+    }
+    // For esp-based frames where the allocas are done outside the prolog, the
+    // esp value may not stabilize to its home value until after all the
+    // fixed-size alloca instructions have executed.  In this case, a stack
+    // adjustment is needed when accessing in-args in order to copy them into
+    // registers.
+    size_t StackAdjBytes = 0;
+    if (!IsEbpBasedFrame && !PrologEmitsFixedAllocas)
+      StackAdjBytes -= FixedAllocaSizeBytes;
+    finishArgumentLowering(Arg, FramePtr, BasicFrameOffset, StackAdjBytes,
+                           InArgsSizeBytes);
+  }
+
+  // Fill in stack offsets for locals.
+  assignVarStackSlots(SortedSpilledVariables, SpillAreaPaddingBytes,
+                      SpillAreaSizeBytes, GlobalsAndSubsequentPaddingSize,
+                      IsEbpBasedFrame);
+  // Assign stack offsets to variables that have been linked to spilled
+  // variables.
+  for (Variable *Var : VariablesLinkedToSpillSlots) {
+    Variable *Linked =
+        (llvm::cast<typename Traits::SpillVariable>(Var))->getLinkedTo();
+    Var->setStackOffset(Linked->getStackOffset());
+  }
+  this->HasComputedFrame = true;
+
+  if (BuildDefs::dump() && Func->isVerbose(IceV_Frame)) {
+    OstreamLocker L(Func->getContext());
+    Ostream &Str = Func->getContext()->getStrDump();
+
+    Str << "Stack layout:\n";
+    uint32_t EspAdjustmentPaddingSize =
+        SpillAreaSizeBytes - LocalsSpillAreaSize -
+        GlobalsAndSubsequentPaddingSize - SpillAreaPaddingBytes -
+        maxOutArgsSizeBytes();
+    Str << " in-args = " << InArgsSizeBytes << " bytes\n"
+        << " return address = " << Traits::X86_RET_IP_SIZE_BYTES << " bytes\n"
+        << " preserved registers = " << PreservedRegsSizeBytes << " bytes\n"
+        << " spill area padding = " << SpillAreaPaddingBytes << " bytes\n"
+        << " globals spill area = " << GlobalsSize << " bytes\n"
+        << " globals-locals spill areas intermediate padding = "
+        << GlobalsAndSubsequentPaddingSize - GlobalsSize << " bytes\n"
+        << " locals spill area = " << LocalsSpillAreaSize << " bytes\n"
+        << " esp alignment padding = " << EspAdjustmentPaddingSize
+        << " bytes\n";
+
+    Str << "Stack details:\n"
+        << " esp adjustment = " << SpillAreaSizeBytes << " bytes\n"
+        << " spill area alignment = " << SpillAreaAlignmentBytes << " bytes\n"
+        << " outgoing args size = " << maxOutArgsSizeBytes() << " bytes\n"
+        << " locals spill area alignment = " << LocalsSlotsAlignmentBytes
+        << " bytes\n"
+        << " is ebp based = " << IsEbpBasedFrame << "\n";
+  }
+}
+
 /// Helper function for addProlog().
 ///
 /// This assumes Arg is an argument passed on the stack. This sets the frame
@@ -920,6 +1191,63 @@ void TargetX86Base<TraitsType>::finishArgumentLowering(
   }
 }
 
+template <typename TraitsType>
+void TargetX86Base<TraitsType>::addEpilog(CfgNode *Node) {
+  InstList &Insts = Node->getInsts();
+  InstList::reverse_iterator RI, E;
+  for (RI = Insts.rbegin(), E = Insts.rend(); RI != E; ++RI) {
+    if (llvm::isa<typename Traits::Insts::Ret>(*RI))
+      break;
+  }
+  if (RI == E)
+    return;
+
+  // Convert the reverse_iterator position into its corresponding (forward)
+  // iterator position.
+  InstList::iterator InsertPoint = RI.base();
+  --InsertPoint;
+  Context.init(Node);
+  Context.setInsertPoint(InsertPoint);
+
+  if (IsEbpBasedFrame) {
+    _unlink_bp();
+  } else {
+    // add stackptr, SpillAreaSizeBytes
+    if (SpillAreaSizeBytes != 0) {
+      _add_sp(Ctx->getConstantInt32(SpillAreaSizeBytes));
+    }
+  }
+
+  // Add pop instructions for preserved registers.
+  llvm::SmallBitVector CalleeSaves =
+      getRegisterSet(RegSet_CalleeSave, RegSet_None);
+  llvm::SmallBitVector Popped(CalleeSaves.size());
+  for (int32_t i = CalleeSaves.size() - 1; i >= 0; --i) {
+    if (static_cast<SizeT>(i) == getFrameReg() && IsEbpBasedFrame)
+      continue;
+    const SizeT Canonical = Traits::getBaseReg(i);
+    if (CalleeSaves[i] && RegsUsed[i]) {
+      Popped[Canonical] = true;
+    }
+  }
+  for (int32_t i = Popped.size() - 1; i >= 0; --i) {
+    if (!Popped[i])
+      continue;
+    assert(i == Traits::getBaseReg(i));
+    _pop(getPhysicalRegister(i, Traits::WordType));
+  }
+
+  if (!NeedSandboxing) {
+    return;
+  }
+  emitSandboxedReturn();
+  if (RI->getSrcSize()) {
+    auto *RetValue = llvm::cast<Variable>(RI->getSrc(0));
+    Context.insert<InstFakeUse>(RetValue);
+  }
+  RI->setDeleted();
+}
+
 template <typename TraitsType> Type TargetX86Base<TraitsType>::stackSlotType() {
   return Traits::WordType;
 }