Index: llvm/include/llvm/MC/MCCodeView.h
===================================================================
--- llvm/include/llvm/MC/MCCodeView.h
+++ llvm/include/llvm/MC/MCCodeView.h
@@ -276,6 +276,10 @@
   /// Emits the offset into the checksum table of the given file number.
   void emitFileChecksumOffset(MCObjectStreamer &OS, unsigned FileNo);
 
+  /// Add something to the string table.  Returns the final string as well as
+  /// offset into the string table.
+  std::pair<StringRef, unsigned> addToStringTable(StringRef S);
+
 private:
   /// The current CodeView line information from the last .cv_loc directive.
   MCCVLoc CurrentCVLoc = MCCVLoc(0, 0, 0, 0, false, true);
@@ -290,10 +294,6 @@
 
   MCDataFragment *getStringTableFragment();
 
-  /// Add something to the string table.  Returns the final string as well as
-  /// offset into the string table.
-  std::pair<StringRef, unsigned> addToStringTable(StringRef S);
-
   /// Get a string table offset.
   unsigned getStringTableOffset(StringRef S);
 
Index: llvm/include/llvm/MC/MCStreamer.h
===================================================================
--- llvm/include/llvm/MC/MCStreamer.h
+++ llvm/include/llvm/MC/MCStreamer.h
@@ -790,6 +790,9 @@
   /// directive.
   virtual void EmitCVFileChecksumOffsetDirective(unsigned FileNo) {}
 
+  /// This implements the CodeView '.cv_fpo_data' assembler directive.
+  virtual void EmitCVFPOData(const MCSymbol *ProcSym, SMLoc Loc = {}) {}
+
   /// Emit the absolute difference between two symbols.
   ///
   /// \pre Offset of \c Hi is greater than the offset \c Lo.
Index: llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
===================================================================
--- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -808,6 +808,10 @@
   if (FuncName.empty())
     FuncName = GlobalValue::dropLLVMManglingEscape(GV->getName());
 
+  // Emit FPO data, but only on 32-bit x86. No other platforms use it.
+  if (Triple(MMI->getModule()->getTargetTriple()).getArch() == Triple::x86)
+    OS.EmitCVFPOData(Fn);
+
   // Emit a symbol subsection, required by VS2012+ to find function boundaries.
   OS.AddComment("Symbol subsection for " + Twine(FuncName));
   MCSymbol *SymbolsEnd = beginCVSubsection(DebugSubsectionKind::Symbols);
Index: llvm/lib/MC/MCAsmStreamer.cpp
===================================================================
--- llvm/lib/MC/MCAsmStreamer.cpp
+++ llvm/lib/MC/MCAsmStreamer.cpp
@@ -248,6 +248,7 @@
   void EmitCVStringTableDirective() override;
   void EmitCVFileChecksumsDirective() override;
   void EmitCVFileChecksumOffsetDirective(unsigned FileNo) override;
+  void EmitCVFPOData(const MCSymbol *ProcSym, SMLoc L) override;
 
   void EmitIdent(StringRef IdentString) override;
   void EmitCFISections(bool EH, bool Debug) override;
@@ -1252,6 +1253,12 @@
   EmitEOL();
 }
 
+void MCAsmStreamer::EmitCVFPOData(const MCSymbol *ProcSym, SMLoc L) {
+  OS << "\t.cv_fpo_data\t";
+  ProcSym->print(OS, MAI);
+  EmitEOL();
+}
+
 void MCAsmStreamer::EmitIdent(StringRef IdentString) {
   assert(MAI->hasIdentDirective() && ".ident directive not supported");
   OS << "\t.ident\t";
Index: llvm/lib/MC/MCParser/AsmParser.cpp
===================================================================
--- llvm/lib/MC/MCParser/AsmParser.cpp
+++ llvm/lib/MC/MCParser/AsmParser.cpp
@@ -503,6 +503,7 @@
     DK_CV_STRINGTABLE,
     DK_CV_FILECHECKSUMS,
     DK_CV_FILECHECKSUM_OFFSET,
+    DK_CV_FPO_DATA,
     DK_CFI_SECTIONS,
     DK_CFI_STARTPROC,
     DK_CFI_ENDPROC,
@@ -580,6 +581,7 @@
   bool parseDirectiveCVStringTable();
   bool parseDirectiveCVFileChecksums();
   bool parseDirectiveCVFileChecksumOffset();
+  bool parseDirectiveCVFPOData();
 
   // .cfi directives
   bool parseDirectiveCFIRegister(SMLoc DirectiveLoc);
@@ -2039,6 +2041,8 @@
       return parseDirectiveCVFileChecksums();
     case DK_CV_FILECHECKSUM_OFFSET:
       return parseDirectiveCVFileChecksumOffset();
+    case DK_CV_FPO_DATA:
+      return parseDirectiveCVFPOData();
     case DK_CFI_SECTIONS:
       return parseDirectiveCFISections();
     case DK_CFI_STARTPROC:
@@ -3791,6 +3795,20 @@
   return false;
 }
 
+/// parseDirectiveCVFPOData
+/// ::= .cv_fpo_data procsym
+bool AsmParser::parseDirectiveCVFPOData() {
+  SMLoc DirLoc = getLexer().getLoc();
+  StringRef ProcName;
+  if (parseIdentifier(ProcName))
+    return TokError("expected symbol name");
+  if (parseEOL("unexpected tokens"))
+    return addErrorSuffix(" in '.cv_fpo_data' directive");
+  MCSymbol *ProcSym = getContext().getOrCreateSymbol(ProcName);
+  getStreamer().EmitCVFPOData(ProcSym, DirLoc);
+  return false;
+}
+
 /// parseDirectiveCFISections
 /// ::= .cfi_sections section [, section]
 bool AsmParser::parseDirectiveCFISections() {
@@ -5174,6 +5192,7 @@
   DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE;
   DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS;
   DirectiveKindMap[".cv_filechecksumoffset"] = DK_CV_FILECHECKSUM_OFFSET;
+  DirectiveKindMap[".cv_fpo_data"] = DK_CV_FPO_DATA;
   DirectiveKindMap[".sleb128"] = DK_SLEB128;
   DirectiveKindMap[".uleb128"] = DK_ULEB128;
   DirectiveKindMap[".cfi_sections"] = DK_CFI_SECTIONS;
Index: llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
===================================================================
--- llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
+++ llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
@@ -7,11 +7,12 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "InstPrinter/X86IntelInstPrinter.h"
 #include "MCTargetDesc/X86BaseInfo.h"
+#include "MCTargetDesc/X86TargetStreamer.h"
 #include "X86AsmInstrumentation.h"
 #include "X86AsmParserCommon.h"
 #include "X86Operand.h"
-#include "InstPrinter/X86IntelInstPrinter.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
@@ -80,6 +81,13 @@
     return Result;
   }
 
+  X86TargetStreamer &getTargetStreamer() {
+    assert(getParser().getStreamer().getTargetStreamer() &&
+           "do not have a target streamer");
+    MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer();
+    return static_cast<X86TargetStreamer &>(TS);
+  }
+
   unsigned MatchInstruction(const OperandVector &Operands, MCInst &Inst,
                             uint64_t &ErrorInfo, bool matchingInlineAsm,
                             unsigned VariantID = 0) {
@@ -839,6 +847,15 @@
   bool ParseDirectiveWord(unsigned Size, SMLoc L);
   bool ParseDirectiveCode(StringRef IDVal, SMLoc L);
 
+  /// CodeView FPO data directives.
+  bool parseDirectiveFPOProc(SMLoc L);
+  bool parseDirectiveFPOSetFrame(SMLoc L);
+  bool parseDirectiveFPOPushReg(SMLoc L);
+  bool parseDirectiveFPOStackAlloc(SMLoc L);
+  bool parseDirectiveFPOEndPrologue(SMLoc L);
+  bool parseDirectiveFPOEndProc(SMLoc L);
+  bool parseDirectiveFPOData(SMLoc L);
+
   bool processInstruction(MCInst &Inst, const OperandVector &Ops);
 
   /// Wrapper around MCStreamer::EmitInstruction(). Possibly adds
@@ -3027,6 +3044,19 @@
     return false;
   } else if (IDVal == ".even")
     return parseDirectiveEven(DirectiveID.getLoc());
+  else if (IDVal == ".cv_fpo_proc")
+    return parseDirectiveFPOProc(DirectiveID.getLoc());
+  else if (IDVal == ".cv_fpo_setframe")
+    return parseDirectiveFPOSetFrame(DirectiveID.getLoc());
+  else if (IDVal == ".cv_fpo_pushreg")
+    return parseDirectiveFPOPushReg(DirectiveID.getLoc());
+  else if (IDVal == ".cv_fpo_stackalloc")
+    return parseDirectiveFPOStackAlloc(DirectiveID.getLoc());
+  else if (IDVal == ".cv_fpo_endprologue")
+    return parseDirectiveFPOEndPrologue(DirectiveID.getLoc());
+  else if (IDVal == ".cv_fpo_endproc")
+    return parseDirectiveFPOEndProc(DirectiveID.getLoc());
+
   return true;
 }
 
@@ -3124,6 +3154,71 @@
   return false;
 }
 
+// .cv_fpo_proc foo
+bool X86AsmParser::parseDirectiveFPOProc(SMLoc L) {
+  MCAsmParser &Parser = getParser();
+  StringRef ProcName;
+  int64_t ParamsSize;
+  if (Parser.parseIdentifier(ProcName))
+    return Parser.TokError("expected symbol name");
+  if (Parser.parseIntToken(ParamsSize, "expected parameter byte count"))
+    return true;
+  if (!isUIntN(32, ParamsSize))
+    return Parser.TokError("parameters size out of range");
+  if (Parser.parseEOL("unexpected tokens"))
+    return addErrorSuffix(" in '.cv_fpo_proc' directive");
+  MCSymbol *ProcSym = getContext().getOrCreateSymbol(ProcName);
+  return getTargetStreamer().emitFPOProc(ProcSym, ParamsSize, L);
+}
+
+// .cv_fpo_setframe ebp
+bool X86AsmParser::parseDirectiveFPOSetFrame(SMLoc L) {
+  MCAsmParser &Parser = getParser();
+  unsigned Reg;
+  SMLoc DummyLoc;
+  if (ParseRegister(Reg, DummyLoc, DummyLoc) ||
+      Parser.parseEOL("unexpected tokens"))
+    return addErrorSuffix(" in '.cv_fpo_setframe' directive");
+  return getTargetStreamer().emitFPOSetFrame(Reg, L);
+}
+
+// .cv_fpo_pushreg ebx
+bool X86AsmParser::parseDirectiveFPOPushReg(SMLoc L) {
+  MCAsmParser &Parser = getParser();
+  unsigned Reg;
+  SMLoc DummyLoc;
+  if (ParseRegister(Reg, DummyLoc, DummyLoc) ||
+      Parser.parseEOL("unexpected tokens"))
+    return addErrorSuffix(" in '.cv_fpo_pushreg' directive");
+  return getTargetStreamer().emitFPOPushReg(Reg, L);
+}
+
+// .cv_fpo_stackalloc 20
+bool X86AsmParser::parseDirectiveFPOStackAlloc(SMLoc L) {
+  MCAsmParser &Parser = getParser();
+  int64_t Offset;
+  if (Parser.parseIntToken(Offset, "expected offset") ||
+      Parser.parseEOL("unexpected tokens"))
+    return addErrorSuffix(" in '.cv_fpo_stackalloc' directive");
+  return getTargetStreamer().emitFPOStackAlloc(Offset, L);
+}
+
+// .cv_fpo_endprologue
+bool X86AsmParser::parseDirectiveFPOEndPrologue(SMLoc L) {
+  MCAsmParser &Parser = getParser();
+  if (Parser.parseEOL("unexpected tokens"))
+    return addErrorSuffix(" in '.cv_fpo_endprologue' directive");
+  return getTargetStreamer().emitFPOEndPrologue(L);
+}
+
+// .cv_fpo_endproc
+bool X86AsmParser::parseDirectiveFPOEndProc(SMLoc L) {
+  MCAsmParser &Parser = getParser();
+  if (Parser.parseEOL("unexpected tokens"))
+    return addErrorSuffix(" in '.cv_fpo_endproc' directive");
+  return getTargetStreamer().emitFPOEndProc(L);
+}
+
 // Force static initialization.
 extern "C" void LLVMInitializeX86AsmParser() {
   RegisterMCAsmParser<X86AsmParser> X(getTheX86_32Target());
Index: llvm/lib/Target/X86/MCTargetDesc/CMakeLists.txt
===================================================================
--- llvm/lib/Target/X86/MCTargetDesc/CMakeLists.txt
+++ llvm/lib/Target/X86/MCTargetDesc/CMakeLists.txt
@@ -5,6 +5,7 @@
   X86MCCodeEmitter.cpp
   X86MachObjectWriter.cpp
   X86ELFObjectWriter.cpp
-  X86WinCOFFStreamer.cpp
   X86WinCOFFObjectWriter.cpp
+  X86WinCOFFStreamer.cpp
+  X86WinCOFFTargetStreamer.cpp
   )
Index: llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h
===================================================================
--- llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h
+++ llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h
@@ -77,6 +77,16 @@
                                      const Triple &TT, StringRef CPU,
                                      const MCTargetOptions &Options);
 
+/// Implements X86-only directives for assembly emission.
+MCTargetStreamer *createX86AsmTargetStreamer(MCStreamer &S,
+                                             formatted_raw_ostream &OS,
+                                             MCInstPrinter *InstPrint,
+                                             bool isVerboseAsm);
+
+/// Implements X86-only directives for object files.
+MCTargetStreamer *createX86ObjectTargetStreamer(MCStreamer &OS,
+                                                const MCSubtargetInfo &STI);
+
 /// Construct an X86 Windows COFF machine code streamer which will generate
 /// PE/COFF format object files.
 ///
Index: llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
===================================================================
--- llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
+++ llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
@@ -319,7 +319,13 @@
     // Register the code emitter.
     TargetRegistry::RegisterMCCodeEmitter(*T, createX86MCCodeEmitter);
 
-    // Register the object streamer.
+    // Register the obj target streamer.
+    TargetRegistry::RegisterObjectTargetStreamer(*T,
+                                                 createX86ObjectTargetStreamer);
+
+    // Register the asm target streamer.
+    TargetRegistry::RegisterAsmTargetStreamer(*T, createX86AsmTargetStreamer);
+
     TargetRegistry::RegisterCOFFStreamer(*T, createX86WinCOFFStreamer);
 
     // Register the MCInstPrinter.
Index: llvm/lib/Target/X86/MCTargetDesc/X86TargetStreamer.h
===================================================================
--- /dev/null
+++ llvm/lib/Target/X86/MCTargetDesc/X86TargetStreamer.h
@@ -0,0 +1,35 @@
+//===- X86TargetStreamer.h ------------------------------*- C++ -*---------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+
+#ifndef LLVM_LIB_TARGET_X86_MCTARGETDESC_X86TARGETSTREAMER_H
+#define LLVM_LIB_TARGET_X86_MCTARGETDESC_X86TARGETSTREAMER_H
+
+#include "llvm/MC/MCStreamer.h"
+
+namespace llvm {
+
+/// X86 target streamer implementing x86-only assembly directives.
+class X86TargetStreamer : public MCTargetStreamer {
+public:
+  X86TargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {}
+
+  virtual bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize,
+                           SMLoc L = {}) = 0;
+  virtual bool emitFPOEndPrologue(SMLoc L = {}) = 0;
+  virtual bool emitFPOEndProc(SMLoc L = {}) = 0;
+  virtual bool emitFPOData(const MCSymbol *ProcSym, SMLoc L = {}) = 0;
+  virtual bool emitFPOPushReg(unsigned Reg, SMLoc L = {}) = 0;
+  virtual bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L = {}) = 0;
+  virtual bool emitFPOSetFrame(unsigned Reg, SMLoc L = {}) = 0;
+};
+
+} // end namespace llvm
+
+#endif
Index: llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp
===================================================================
--- llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp
+++ llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "X86MCTargetDesc.h"
+#include "X86TargetStreamer.h"
 #include "llvm/MC/MCAsmBackend.h"
 #include "llvm/MC/MCWin64EH.h"
 #include "llvm/MC/MCWinCOFFStreamer.h"
@@ -24,6 +25,7 @@
 
   void EmitWinEHHandlerData(SMLoc Loc) override;
   void EmitWindowsUnwindTables() override;
+  void EmitCVFPOData(const MCSymbol *ProcSym, SMLoc Loc) override;
   void FinishImpl() override;
 };
 
@@ -41,6 +43,12 @@
   EHStreamer.Emit(*this);
 }
 
+void X86WinCOFFStreamer::EmitCVFPOData(const MCSymbol *ProcSym, SMLoc Loc) {
+  X86TargetStreamer *XTS =
+      static_cast<X86TargetStreamer *>(getTargetStreamer());
+  XTS->emitFPOData(ProcSym, Loc);
+}
+
 void X86WinCOFFStreamer::FinishImpl() {
   EmitFrames(nullptr);
   EmitWindowsUnwindTables();
Index: llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp
===================================================================
--- /dev/null
+++ llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp
@@ -0,0 +1,410 @@
+//===-- X86WinCOFFTargetStreamer.cpp ----------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86MCTargetDesc.h"
+#include "X86TargetStreamer.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/MC/MCCodeView.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/FormattedStream.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+namespace {
+/// Implements Windows x86-only directives for assembly emission.
+class X86WinCOFFAsmTargetStreamer : public X86TargetStreamer {
+  formatted_raw_ostream &OS;
+  MCInstPrinter &InstPrinter;
+
+public:
+  X86WinCOFFAsmTargetStreamer(MCStreamer &S, formatted_raw_ostream &OS,
+                              MCInstPrinter &InstPrinter)
+      : X86TargetStreamer(S), OS(OS), InstPrinter(InstPrinter) {}
+
+  bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize,
+                   SMLoc L) override;
+  bool emitFPOEndPrologue(SMLoc L) override;
+  bool emitFPOEndProc(SMLoc L) override;
+  bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override;
+  bool emitFPOPushReg(unsigned Reg, SMLoc L) override;
+  bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override;
+  bool emitFPOSetFrame(unsigned Reg, SMLoc L) override;
+};
+
+/// Represents a single FPO directive.
+struct FPOInstruction {
+  MCSymbol *Label;
+  enum Operation {
+    PushReg,
+    StackAlloc,
+    SetFrame,
+  } Op;
+  unsigned RegOrOffset;
+};
+
+struct FPOData {
+  const MCSymbol *Function = nullptr;
+  MCSymbol *Begin = nullptr;
+  MCSymbol *PrologueEnd = nullptr;
+  MCSymbol *End = nullptr;
+  unsigned ParamsSize = 0;
+
+  SmallVector<FPOInstruction, 5> Instructions;
+};
+
+/// Implements Windows x86-only directives for object emission.
+class X86WinCOFFTargetStreamer : public X86TargetStreamer {
+  /// Map from function symbol to its FPO data.
+  DenseMap<const MCSymbol *, std::unique_ptr<FPOData>> AllFPOData;
+
+  /// Current FPO data created by .cv_fpo_proc.
+  std::unique_ptr<FPOData> CurFPOData;
+
+  bool haveOpenFPOData() { return !!CurFPOData; }
+
+  /// Diagnoses an error at L if we are not in an FPO prologue. Return true on
+  /// error.
+  bool checkInFPOPrologue(SMLoc L);
+
+  MCSymbol *emitFPOLabel();
+
+  MCContext &getContext() { return getStreamer().getContext(); }
+
+public:
+  X86WinCOFFTargetStreamer(MCStreamer &S) : X86TargetStreamer(S) {}
+
+  bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize,
+                   SMLoc L) override;
+  bool emitFPOEndPrologue(SMLoc L) override;
+  bool emitFPOEndProc(SMLoc L) override;
+  bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override;
+  bool emitFPOPushReg(unsigned Reg, SMLoc L) override;
+  bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override;
+  bool emitFPOSetFrame(unsigned Reg, SMLoc L) override;
+};
+} // end namespace
+
+bool X86WinCOFFAsmTargetStreamer::emitFPOProc(const MCSymbol *ProcSym,
+                                              unsigned ParamsSize, SMLoc L) {
+  OS << "\t.cv_fpo_proc\t";
+  ProcSym->print(OS, getStreamer().getContext().getAsmInfo());
+  OS << ' ' << ParamsSize << '\n';
+  return false;
+}
+
+bool X86WinCOFFAsmTargetStreamer::emitFPOEndPrologue(SMLoc L) {
+  OS << "\t.cv_fpo_endprologue\n";
+  return false;
+}
+
+bool X86WinCOFFAsmTargetStreamer::emitFPOEndProc(SMLoc L) {
+  OS << "\t.cv_fpo_endproc\n";
+  return false;
+}
+
+bool X86WinCOFFAsmTargetStreamer::emitFPOData(const MCSymbol *ProcSym,
+                                              SMLoc L) {
+  OS << "\t.cv_fpo_data\t";
+  ProcSym->print(OS, getStreamer().getContext().getAsmInfo());
+  OS << '\n';
+  return false;
+}
+
+bool X86WinCOFFAsmTargetStreamer::emitFPOPushReg(unsigned Reg, SMLoc L) {
+  OS << "\t.cv_fpo_pushreg\t";
+  InstPrinter.printRegName(OS, Reg);
+  OS << '\n';
+  return false;
+}
+
+bool X86WinCOFFAsmTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc,
+                                                    SMLoc L) {
+  OS << "\t.cv_fpo_stackalloc\t" << StackAlloc << '\n';
+  return false;
+}
+
+bool X86WinCOFFAsmTargetStreamer::emitFPOSetFrame(unsigned Reg, SMLoc L) {
+  OS << "\t.cv_fpo_setframe\t";
+  InstPrinter.printRegName(OS, Reg);
+  OS << '\n';
+  return false;
+}
+
+bool X86WinCOFFTargetStreamer::checkInFPOPrologue(SMLoc L) {
+  if (!haveOpenFPOData() || CurFPOData->PrologueEnd) {
+    getContext().reportError(
+        L,
+        "directive must appear between .cv_fpo_proc and .cv_fpo_endprologue");
+    return true;
+  }
+  return false;
+}
+
+MCSymbol *X86WinCOFFTargetStreamer::emitFPOLabel() {
+  MCSymbol *Label = getContext().createTempSymbol("cfi", true);
+  getStreamer().EmitLabel(Label);
+  return Label;
+}
+
+bool X86WinCOFFTargetStreamer::emitFPOProc(const MCSymbol *ProcSym,
+                                           unsigned ParamsSize, SMLoc L) {
+  if (haveOpenFPOData()) {
+    getContext().reportError(
+        L, "opening new .cv_fpo_proc before closing previous frame");
+    return true;
+  }
+  CurFPOData = llvm::make_unique<FPOData>();
+  CurFPOData->Function = ProcSym;
+  CurFPOData->Begin = emitFPOLabel();
+  CurFPOData->ParamsSize = ParamsSize;
+  return false;
+}
+
+bool X86WinCOFFTargetStreamer::emitFPOEndProc(SMLoc L) {
+  if (!haveOpenFPOData()) {
+    getContext().reportError(L, ".cv_fpo_endproc must appear after .cv_proc");
+    return true;
+  }
+  if (!CurFPOData->PrologueEnd) {
+    // Complain if there were prologue setup instructions but no end prologue.
+    if (!CurFPOData->Instructions.empty()) {
+      getContext().reportError(L, "missing .cv_fpo_endprologue");
+      CurFPOData->Instructions.clear();
+    }
+
+    // Claim there is a zero-length prologue to make the label math work out
+    // later.
+    CurFPOData->PrologueEnd = CurFPOData->Begin;
+  }
+
+  CurFPOData->End = emitFPOLabel();
+  const MCSymbol *Fn = CurFPOData->Function;
+  AllFPOData.insert({Fn, std::move(CurFPOData)});
+  return false;
+}
+
+bool X86WinCOFFTargetStreamer::emitFPOSetFrame(unsigned Reg, SMLoc L) {
+  if (checkInFPOPrologue(L))
+    return true;
+  FPOInstruction Inst;
+  Inst.Label = emitFPOLabel();
+  Inst.Op = FPOInstruction::SetFrame;
+  Inst.RegOrOffset = Reg;
+  CurFPOData->Instructions.push_back(Inst);
+  return false;
+}
+
+bool X86WinCOFFTargetStreamer::emitFPOPushReg(unsigned Reg, SMLoc L) {
+  if (checkInFPOPrologue(L))
+    return true;
+  FPOInstruction Inst;
+  Inst.Label = emitFPOLabel();
+  Inst.Op = FPOInstruction::PushReg;
+  Inst.RegOrOffset = Reg;
+  CurFPOData->Instructions.push_back(Inst);
+  return false;
+}
+
+bool X86WinCOFFTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) {
+  if (checkInFPOPrologue(L))
+    return true;
+  FPOInstruction Inst;
+  Inst.Label = emitFPOLabel();
+  Inst.Op = FPOInstruction::StackAlloc;
+  Inst.RegOrOffset = StackAlloc;
+  CurFPOData->Instructions.push_back(Inst);
+  return false;
+}
+
+bool X86WinCOFFTargetStreamer::emitFPOEndPrologue(SMLoc L) {
+  if (checkInFPOPrologue(L))
+    return true;
+  CurFPOData->PrologueEnd = emitFPOLabel();
+  return false;
+}
+
+namespace {
+struct RegSaveOffset {
+  unsigned Reg = 0;
+  unsigned Offset = 0;
+};
+
+struct FPOStateMachine {
+  explicit FPOStateMachine(const FPOData *FPO) : FPO(FPO) {}
+
+  const FPOData *FPO = nullptr;
+  unsigned FrameReg = 0;
+  unsigned FrameRegOff = 0;
+  unsigned CurOffset = 0;
+  unsigned LocalSize = 0;
+  unsigned SavedRegSize = 0;
+  unsigned Flags = 0; // FIXME: Set HasSEH / HasEH.
+
+  SmallString<128> FrameFunc;
+
+  SmallVector<RegSaveOffset, 4> RegSaveOffsets;
+
+  void emitFrameDataRecord(MCStreamer &OS, MCSymbol *Label);
+};
+} // end namespace
+
+static Printable printFPOReg(const MCRegisterInfo *MRI, unsigned LLVMReg) {
+  return Printable([MRI, LLVMReg](raw_ostream &OS) {
+    switch (LLVMReg) {
+    // MSVC only seems to emit symbolic register names for EIP, EBP, and ESP,
+    // but the format seems to support more than that, so we emit them.
+    case X86::EAX: OS << "$eax"; break;
+    case X86::EBX: OS << "$ebx"; break;
+    case X86::ECX: OS << "$ecx"; break;
+    case X86::EDX: OS << "$edx"; break;
+    case X86::EDI: OS << "$edi"; break;
+    case X86::ESI: OS << "$esi"; break;
+    case X86::ESP: OS << "$esp"; break;
+    case X86::EBP: OS << "$ebp"; break;
+    case X86::EIP: OS << "$eip"; break;
+    // Otherwise, get the codeview register number and print $N.
+    default:
+      OS << '$' << MRI->getCodeViewRegNum(LLVMReg);
+      break;
+    }
+  });
+}
+
+void FPOStateMachine::emitFrameDataRecord(MCStreamer &OS, MCSymbol *Label) {
+  unsigned CurFlags = Flags;
+  if (Label == FPO->Begin)
+    CurFlags |= FrameData::IsFunctionStart;
+
+  // Compute the new FrameFunc string.
+  FrameFunc.clear();
+  raw_svector_ostream FuncOS(FrameFunc);
+  const MCRegisterInfo *MRI = OS.getContext().getRegisterInfo();
+  if (FrameReg) {
+    // CFA is FrameReg + FrameRegOff.
+    FuncOS << "$T0 " << printFPOReg(MRI, FrameReg) << " " << FrameRegOff
+           << " + = ";
+  } else {
+    // The address of return address is ESP + CurOffset, but we use .raSearch to
+    // match MSVC. This seems to ask the debugger to subtract some combination
+    // of LocalSize and SavedRegSize from ESP and grovel around in that memory
+    // to find the address of a plausible return address.
+    FuncOS << "$T0 .raSearch = ";
+  }
+
+  // Caller's $eip should be dereferenced CFA, and $esp should be CFA plus 4.
+  FuncOS << "$eip $T0 ^ = $esp $T0 4 + = ";
+
+  // Each saved register is stored at an unchanging negative CFA offset.
+  for (RegSaveOffset RO : RegSaveOffsets)
+    FuncOS << printFPOReg(MRI, RO.Reg) << " $T0 " << RO.Offset << " - ^ = ";
+
+  // Add it to the CV string table.
+  CodeViewContext &CVCtx = OS.getContext().getCVContext();
+  unsigned FrameFuncStrTabOff = CVCtx.addToStringTable(FuncOS.str()).second;
+
+  // The FrameData record format is:
+  //   ulittle32_t RvaStart;
+  //   ulittle32_t CodeSize;
+  //   ulittle32_t LocalSize;
+  //   ulittle32_t ParamsSize;
+  //   ulittle32_t MaxStackSize;
+  //   ulittle32_t FrameFunc; // String table offset
+  //   ulittle16_t PrologSize;
+  //   ulittle16_t SavedRegsSize;
+  //   ulittle32_t Flags;
+
+  OS.emitAbsoluteSymbolDiff(Label, FPO->Begin, 4); // RvaStart
+  OS.emitAbsoluteSymbolDiff(FPO->End, Label, 4);   // CodeSize
+  OS.EmitIntValue(LocalSize, 4);
+  OS.EmitIntValue(FPO->ParamsSize, 4);
+  OS.EmitIntValue(0, 4); // MaxStackSize
+  OS.EmitIntValue(FrameFuncStrTabOff, 4); // FrameFunc
+  OS.emitAbsoluteSymbolDiff(FPO->PrologueEnd, Label, 2);
+  OS.EmitIntValue(SavedRegSize, 2);
+  OS.EmitIntValue(CurFlags, 4);
+}
+
+/// Compute and emit the real CodeView FrameData subsection.
+bool X86WinCOFFTargetStreamer::emitFPOData(const MCSymbol *ProcSym, SMLoc L) {
+  MCStreamer &OS = getStreamer();
+  MCContext &Ctx = OS.getContext();
+
+  auto I = AllFPOData.find(ProcSym);
+  if (I == AllFPOData.end()) {
+    Ctx.reportError(L, Twine("no FPO data found for symbol ") +
+                           ProcSym->getName());
+    return true;
+  }
+  const FPOData *FPO = I->second.get();
+  assert(FPO->Begin && FPO->End && FPO->PrologueEnd && "missing FPO label");
+
+  MCSymbol *FrameBegin = Ctx.createTempSymbol(),
+           *FrameEnd = Ctx.createTempSymbol();
+
+  OS.EmitIntValue(unsigned(DebugSubsectionKind::FrameData), 4);
+  OS.emitAbsoluteSymbolDiff(FrameEnd, FrameBegin, 4);
+  OS.EmitLabel(FrameBegin);
+
+  // Start with the RVA of the function in question.
+  OS.EmitValue(MCSymbolRefExpr::create(FPO->Function,
+                                       MCSymbolRefExpr::VK_COFF_IMGREL32, Ctx),
+               4);
+
+  // Emit a sequence of FrameData records.
+  FPOStateMachine FSM(FPO);
+
+  FSM.emitFrameDataRecord(OS, FPO->Begin);
+  for (const FPOInstruction &Inst : FPO->Instructions) {
+    switch (Inst.Op) {
+    case FPOInstruction::PushReg:
+      FSM.CurOffset += 4;
+      FSM.SavedRegSize += 4;
+      FSM.RegSaveOffsets.push_back({Inst.RegOrOffset, FSM.CurOffset});
+      break;
+    case FPOInstruction::SetFrame:
+      FSM.FrameReg = Inst.RegOrOffset;
+      FSM.FrameRegOff = FSM.CurOffset;
+      break;
+    case FPOInstruction::StackAlloc:
+      FSM.CurOffset += Inst.RegOrOffset;
+      FSM.LocalSize += Inst.RegOrOffset;
+      // No need to emit FrameData for stack allocations with a frame pointer.
+      if (FSM.FrameReg)
+        continue;
+      break;
+    }
+    FSM.emitFrameDataRecord(OS, Inst.Label);
+  }
+
+  OS.EmitValueToAlignment(4, 0);
+  OS.EmitLabel(FrameEnd);
+  return false;
+}
+
+MCTargetStreamer *llvm::createX86AsmTargetStreamer(MCStreamer &S,
+                                                   formatted_raw_ostream &OS,
+                                                   MCInstPrinter *InstPrinter,
+                                                   bool IsVerboseAsm) {
+  // FIXME: This makes it so we textually assemble COFF directives on ELF.
+  // That's kind of nonsensical.
+  return new X86WinCOFFAsmTargetStreamer(S, OS, *InstPrinter);
+}
+
+MCTargetStreamer *
+llvm::createX86ObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
+  // No need to register a target streamer.
+  if (!STI.getTargetTriple().isOSBinFormatCOFF())
+    return nullptr;
+  // Registers itself to the MCStreamer.
+  return new X86WinCOFFTargetStreamer(S);
+}
Index: llvm/lib/Target/X86/X86AsmPrinter.h
===================================================================
--- llvm/lib/Target/X86/X86AsmPrinter.h
+++ llvm/lib/Target/X86/X86AsmPrinter.h
@@ -30,6 +30,7 @@
   StackMaps SM;
   FaultMaps FM;
   std::unique_ptr<MCCodeEmitter> CodeEmitter;
+  bool EmitFPOData = false;
 
   // This utility class tracks the length of a stackmap instruction's 'shadow'.
   // It is used by the X86AsmPrinter to ensure that the stackmap shadow
@@ -99,6 +100,9 @@
   // function.
   void EmitXRayTable();
 
+  // Choose between emitting .seh_ directives and .cv_fpo_ directives.
+  void EmitSEHInstruction(const MachineInstr *MI);
+
 public:
   explicit X86AsmPrinter(TargetMachine &TM,
                          std::unique_ptr<MCStreamer> Streamer)
@@ -137,6 +141,8 @@
   }
 
   bool runOnMachineFunction(MachineFunction &F) override;
+  void EmitFunctionBodyStart() override;
+  void EmitFunctionBodyEnd() override;
 };
 
 } // end namespace llvm
Index: llvm/lib/Target/X86/X86AsmPrinter.cpp
===================================================================
--- llvm/lib/Target/X86/X86AsmPrinter.cpp
+++ llvm/lib/Target/X86/X86AsmPrinter.cpp
@@ -15,6 +15,7 @@
 #include "X86AsmPrinter.h"
 #include "InstPrinter/X86ATTInstPrinter.h"
 #include "MCTargetDesc/X86BaseInfo.h"
+#include "MCTargetDesc/X86TargetStreamer.h"
 #include "X86InstrInfo.h"
 #include "X86MachineFunctionInfo.h"
 #include "llvm/BinaryFormat/COFF.h"
@@ -51,9 +52,12 @@
 
   SMShadowTracker.startFunction(MF);
   CodeEmitter.reset(TM.getTarget().createMCCodeEmitter(
-      *MF.getSubtarget().getInstrInfo(), *MF.getSubtarget().getRegisterInfo(),
+      *Subtarget->getInstrInfo(), *Subtarget->getRegisterInfo(),
       MF.getContext()));
 
+  EmitFPOData =
+      Subtarget->isTargetWin32() && MF.getMMI().getModule()->getCodeViewFlag();
+
   SetupMachineFunction(MF);
 
   if (Subtarget->isTargetCOFF()) {
@@ -72,10 +76,30 @@
   // Emit the XRay table for this function.
   emitXRayTable();
 
+  EmitFPOData = false;
+
   // We didn't modify anything.
   return false;
 }
 
+void X86AsmPrinter::EmitFunctionBodyStart() {
+  if (EmitFPOData) {
+    X86TargetStreamer *XTS =
+        static_cast<X86TargetStreamer *>(OutStreamer->getTargetStreamer());
+    unsigned ParamsSize =
+        MF->getInfo<X86MachineFunctionInfo>()->getArgumentStackSize();
+    XTS->emitFPOProc(CurrentFnSym, ParamsSize);
+  }
+}
+
+void X86AsmPrinter::EmitFunctionBodyEnd() {
+  if (EmitFPOData) {
+    X86TargetStreamer *XTS =
+        static_cast<X86TargetStreamer *>(OutStreamer->getTargetStreamer());
+    XTS->emitFPOEndProc();
+  }
+}
+
 /// printSymbolOperand - Print a raw symbol reference operand.  This handles
 /// jump tables, constant pools, global address and external symbols, all of
 /// which print to a label with various suffixes for relocation types etc.
Index: llvm/lib/Target/X86/X86FrameLowering.cpp
===================================================================
--- llvm/lib/Target/X86/X86FrameLowering.cpp
+++ llvm/lib/Target/X86/X86FrameLowering.cpp
@@ -924,6 +924,7 @@
 
   Notes:
   - .seh directives are emitted only for Windows 64 ABI
+  - .cv_fpo directives are emitted on win32 when emitting CodeView
   - .cfi directives are emitted for all other ABIs
   - for 32-bit code, substitute %e?? registers for %r??
 */
@@ -949,7 +950,9 @@
   bool HasFP = hasFP(MF);
   bool IsWin64CC = STI.isCallingConvWin64(Fn->getCallingConv());
   bool IsWin64Prologue = MF.getTarget().getMCAsmInfo()->usesWindowsCFI();
-  bool NeedsWinCFI = IsWin64Prologue && Fn->needsUnwindTableEntry();
+  bool NeedsWin64CFI = IsWin64Prologue && Fn->needsUnwindTableEntry();
+  bool NeedsWinFPO = STI.isTargetWin32() && MMI.getModule()->getCodeViewFlag();
+  bool NeedsWinCFI = NeedsWin64CFI || NeedsWinFPO;
   bool NeedsDwarfCFI =
       !IsWin64Prologue && (MMI.hasDebugInfo() || Fn->needsUnwindTableEntry());
   unsigned FramePtr = TRI->getFrameRegister(MF);
@@ -958,7 +961,7 @@
           ? getX86SubSuperRegister(FramePtr, 64) : FramePtr;
   unsigned BasePtr = TRI->getBaseRegister();
   bool HasWinCFI = false;
-  
+
   // Debug location must be unknown since the first debug location is used
   // to determine the end of the prologue.
   DebugLoc DL;
@@ -1120,6 +1123,15 @@
         BuildCFI(MBB, MBBI, DL, MCCFIInstruction::createDefCfaRegister(
                                     nullptr, DwarfFramePtr));
       }
+
+      if (NeedsWinFPO) {
+        // .cv_fpo_setframe $FramePtr
+        HasWinCFI = true;
+        BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_SetFrame))
+            .addImm(FramePtr)
+            .addImm(0)
+            .setMIFlag(MachineInstr::FrameSetup);
+      }
     }
   } else {
     assert(!IsFunclet && "funclets without FPs not yet implemented");
@@ -1155,8 +1167,9 @@
 
     if (NeedsWinCFI) {
       HasWinCFI = true;
-      BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_PushReg)).addImm(Reg).setMIFlag(
-          MachineInstr::FrameSetup);
+      BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_PushReg))
+          .addImm(Reg)
+          .setMIFlag(MachineInstr::FrameSetup);
     }
   }
 
@@ -1295,6 +1308,7 @@
 
     // If this is not a funclet, emit the CFI describing our frame pointer.
     if (NeedsWinCFI && !IsFunclet) {
+      assert(!NeedsWinFPO && "this setframe incompatible with FPO data");
       HasWinCFI = true;
       BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_SetFrame))
           .addImm(FramePtr)
@@ -1333,6 +1347,7 @@
           Offset += SEHFrameOffset;
 
           HasWinCFI = true;
+          assert(!NeedsWinFPO && "SEH_SaveXMM incompatible with FPO data");
           BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_SaveXMM))
               .addImm(Reg)
               .addImm(Offset)
@@ -1534,7 +1549,7 @@
       Is64BitILP32 ? getX86SubSuperRegister(FramePtr, 64) : FramePtr;
 
   bool IsWin64Prologue = MF.getTarget().getMCAsmInfo()->usesWindowsCFI();
-  bool NeedsWinCFI =
+  bool NeedsWin64CFI =
       IsWin64Prologue && MF.getFunction()->needsUnwindTableEntry();
   bool IsFunclet = MBBI == MBB.end() ? false : isFuncletReturnInstr(*MBBI);
 
@@ -1639,7 +1654,7 @@
   // into the epilogue.  To cope with that, we insert an epilogue marker here,
   // then replace it with a 'nop' if it ends up immediately after a CALL in the
   // final emitted code.
-  if (NeedsWinCFI && MF.hasWinCFI())
+  if (NeedsWin64CFI && MF.hasWinCFI())
     BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_Epilogue));
 
   if (Terminator == MBB.end() || !isTailCallOpcode(Terminator->getOpcode())) {
Index: llvm/lib/Target/X86/X86MCInstLower.cpp
===================================================================
--- llvm/lib/Target/X86/X86MCInstLower.cpp
+++ llvm/lib/Target/X86/X86MCInstLower.cpp
@@ -15,6 +15,7 @@
 #include "InstPrinter/X86ATTInstPrinter.h"
 #include "InstPrinter/X86InstComments.h"
 #include "MCTargetDesc/X86BaseInfo.h"
+#include "MCTargetDesc/X86TargetStreamer.h"
 #include "Utils/X86ShuffleDecode.h"
 #include "X86AsmPrinter.h"
 #include "X86RegisterInfo.h"
@@ -1363,6 +1364,82 @@
   }
 }
 
+void X86AsmPrinter::EmitSEHInstruction(const MachineInstr *MI) {
+  assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
+  assert(getSubtarget().isOSWindows() && "SEH_ instruction Windows only");
+  const X86RegisterInfo *RI =
+      MF->getSubtarget<X86Subtarget>().getRegisterInfo();
+
+  // Use the .cv_fpo directives if we're emitting CodeView on 32-bit x86.
+  if (EmitFPOData) {
+    X86TargetStreamer *XTS =
+        static_cast<X86TargetStreamer *>(OutStreamer->getTargetStreamer());
+    switch (MI->getOpcode()) {
+    case X86::SEH_PushReg:
+      XTS->emitFPOPushReg(MI->getOperand(0).getImm());
+      break;
+    case X86::SEH_StackAlloc:
+      XTS->emitFPOStackAlloc(MI->getOperand(0).getImm());
+      break;
+    case X86::SEH_SetFrame:
+      assert(MI->getOperand(1).getImm() == 0 &&
+             ".cv_fpo_setframe takes no offset");
+      XTS->emitFPOSetFrame(MI->getOperand(0).getImm());
+      break;
+    case X86::SEH_EndPrologue:
+      XTS->emitFPOEndPrologue();
+      break;
+    case X86::SEH_SaveReg:
+    case X86::SEH_SaveXMM:
+    case X86::SEH_PushFrame:
+      llvm_unreachable("SEH_ directive incompatible with FPO");
+      break;
+    default:
+      llvm_unreachable("expected SEH_ instruction");
+    }
+    return;
+  }
+
+  // Otherwise, use the .seh_ directives for all other Windows platforms.
+  switch (MI->getOpcode()) {
+  case X86::SEH_PushReg:
+    OutStreamer->EmitWinCFIPushReg(
+        RI->getSEHRegNum(MI->getOperand(0).getImm()));
+    break;
+
+  case X86::SEH_SaveReg:
+    OutStreamer->EmitWinCFISaveReg(RI->getSEHRegNum(MI->getOperand(0).getImm()),
+                                   MI->getOperand(1).getImm());
+    break;
+
+  case X86::SEH_SaveXMM:
+    OutStreamer->EmitWinCFISaveXMM(RI->getSEHRegNum(MI->getOperand(0).getImm()),
+                                   MI->getOperand(1).getImm());
+    break;
+
+  case X86::SEH_StackAlloc:
+    OutStreamer->EmitWinCFIAllocStack(MI->getOperand(0).getImm());
+    break;
+
+  case X86::SEH_SetFrame:
+    OutStreamer->EmitWinCFISetFrame(
+        RI->getSEHRegNum(MI->getOperand(0).getImm()),
+        MI->getOperand(1).getImm());
+    break;
+
+  case X86::SEH_PushFrame:
+    OutStreamer->EmitWinCFIPushFrame(MI->getOperand(0).getImm());
+    break;
+
+  case X86::SEH_EndPrologue:
+    OutStreamer->EmitWinCFIEndProlog();
+    break;
+
+  default:
+    llvm_unreachable("expected SEH_ instruction");
+  }
+}
+
 void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {
   X86MCInstLower MCInstLowering(*MF, *this);
   const X86RegisterInfo *RI = MF->getSubtarget<X86Subtarget>().getRegisterInfo();
@@ -1540,41 +1617,13 @@
     return;
 
   case X86::SEH_PushReg:
-    assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
-    OutStreamer->EmitWinCFIPushReg(RI->getSEHRegNum(MI->getOperand(0).getImm()));
-    return;
-
   case X86::SEH_SaveReg:
-    assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
-    OutStreamer->EmitWinCFISaveReg(RI->getSEHRegNum(MI->getOperand(0).getImm()),
-                                   MI->getOperand(1).getImm());
-    return;
-
   case X86::SEH_SaveXMM:
-    assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
-    OutStreamer->EmitWinCFISaveXMM(RI->getSEHRegNum(MI->getOperand(0).getImm()),
-                                   MI->getOperand(1).getImm());
-    return;
-
   case X86::SEH_StackAlloc:
-    assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
-    OutStreamer->EmitWinCFIAllocStack(MI->getOperand(0).getImm());
-    return;
-
   case X86::SEH_SetFrame:
-    assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
-    OutStreamer->EmitWinCFISetFrame(RI->getSEHRegNum(MI->getOperand(0).getImm()),
-                                    MI->getOperand(1).getImm());
-    return;
-
   case X86::SEH_PushFrame:
-    assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
-    OutStreamer->EmitWinCFIPushFrame(MI->getOperand(0).getImm());
-    return;
-
   case X86::SEH_EndPrologue:
-    assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
-    OutStreamer->EmitWinCFIEndProlog();
+    EmitSEHInstruction(MI);
     return;
 
   case X86::SEH_Epilogue: {
Index: llvm/lib/Target/X86/X86Subtarget.h
===================================================================
--- llvm/lib/Target/X86/X86Subtarget.h
+++ llvm/lib/Target/X86/X86Subtarget.h
@@ -592,13 +592,9 @@
 
   bool isOSWindows() const { return TargetTriple.isOSWindows(); }
 
-  bool isTargetWin64() const {
-    return In64BitMode && TargetTriple.isOSWindows();
-  }
+  bool isTargetWin64() const { return In64BitMode && isOSWindows(); }
 
-  bool isTargetWin32() const {
-    return !In64BitMode && (isTargetCygMing() || isTargetKnownWindowsMSVC());
-  }
+  bool isTargetWin32() const { return !In64BitMode && isOSWindows(); }
 
   bool isPICStyleGOT() const { return PICStyle == PICStyles::GOT; }
   bool isPICStyleRIPRel() const { return PICStyle == PICStyles::RIPRel; }
Index: llvm/test/DebugInfo/COFF/asan-module-ctor.ll
===================================================================
--- llvm/test/DebugInfo/COFF/asan-module-ctor.ll
+++ llvm/test/DebugInfo/COFF/asan-module-ctor.ll
@@ -10,7 +10,7 @@
 ; The module ctor has no debug info.  All we have to do is don't crash.
 ; X86: _asan.module_ctor:
 ; X86-NEXT: L{{.*}}:
-; X86-NEXT: # BB
+; X86:      # BB
 ; X86-NEXT: calll   ___asan_init_v3
 ; X86-NEXT: retl
 
Index: llvm/test/DebugInfo/COFF/fpo-argsize.ll
===================================================================
--- /dev/null
+++ llvm/test/DebugInfo/COFF/fpo-argsize.ll
@@ -0,0 +1,454 @@
+; RUN: llc < %s | grep cv_fpo_proc | FileCheck %s
+
+; C++ source:
+; extern "C" {
+; extern int g;
+; 
+; void cdecl1(int a) { g += a; }
+; void cdecl2(int a, int b) { g += a + b; }
+; void cdecl3(int a, int b, int c) { g += a + b + c; }
+; 
+; void __fastcall fastcall1(int a) { g += a; }
+; void __fastcall fastcall2(int a, int b) { g += a + b; }
+; void __fastcall fastcall3(int a, int b, int c) { g += a + b + c; }
+; 
+; void __stdcall stdcall1(int a) { g += a; }
+; void __stdcall stdcall2(int a, int b) { g += a + b; }
+; void __stdcall stdcall3(int a, int b, int c) { g += a + b + c; }
+; }
+; 
+; struct Foo {
+;   void thiscall1(int a);
+;   void thiscall2(int a, int b);
+;   void thiscall3(int a, int b, int c);
+; };
+; 
+; void Foo::thiscall1(int a) { g += a; }
+; void Foo::thiscall2(int a, int b) { g += a + b; }
+; void Foo::thiscall3(int a, int b, int c) { g += a + b + c; }
+
+; CHECK: .cv_fpo_proc    _cdecl1 4
+; CHECK: .cv_fpo_proc    _cdecl2 8
+; CHECK: .cv_fpo_proc    _cdecl3 12
+
+; First two args are in registers and don't count.
+; CHECK: .cv_fpo_proc    @fastcall1@4 0
+; CHECK: .cv_fpo_proc    @fastcall2@8 0
+; CHECK: .cv_fpo_proc    @fastcall3@12 4
+
+; CHECK: .cv_fpo_proc    _stdcall1@4 4
+; CHECK: .cv_fpo_proc    _stdcall2@8 8
+; CHECK: .cv_fpo_proc    _stdcall3@12 12
+
+; 'this' is in ecx and doesn't count.
+; CHECK: .cv_fpo_proc    "?thiscall1@Foo@@QAEXH@Z" 4
+; CHECK: .cv_fpo_proc    "?thiscall2@Foo@@QAEXHH@Z" 8
+; CHECK: .cv_fpo_proc    "?thiscall3@Foo@@QAEXHHH@Z" 12
+
+; ModuleID = 't.c'
+source_filename = "t.c"
+target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+target triple = "i386-pc-windows-msvc19.11.25508"
+
+%struct.Foo = type { i8 }
+
+@g = external global i32, align 4
+
+; Function Attrs: noinline nounwind optnone
+define void @cdecl1(i32 %a) #0 !dbg !8 {
+entry:
+  %a.addr = alloca i32, align 4
+  store i32 %a, i32* %a.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !12, metadata !DIExpression()), !dbg !13
+  %0 = load i32, i32* %a.addr, align 4, !dbg !14
+  %1 = load i32, i32* @g, align 4, !dbg !15
+  %add = add nsw i32 %1, %0, !dbg !15
+  store i32 %add, i32* @g, align 4, !dbg !15
+  ret void, !dbg !16
+}
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: noinline nounwind optnone
+define void @cdecl2(i32 %a, i32 %b) #0 !dbg !17 {
+entry:
+  %b.addr = alloca i32, align 4
+  %a.addr = alloca i32, align 4
+  store i32 %b, i32* %b.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !20, metadata !DIExpression()), !dbg !21
+  store i32 %a, i32* %a.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !22, metadata !DIExpression()), !dbg !23
+  %0 = load i32, i32* %a.addr, align 4, !dbg !24
+  %1 = load i32, i32* %b.addr, align 4, !dbg !25
+  %add = add nsw i32 %0, %1, !dbg !26
+  %2 = load i32, i32* @g, align 4, !dbg !27
+  %add1 = add nsw i32 %2, %add, !dbg !27
+  store i32 %add1, i32* @g, align 4, !dbg !27
+  ret void, !dbg !28
+}
+
+; Function Attrs: noinline nounwind optnone
+define void @cdecl3(i32 %a, i32 %b, i32 %c) #0 !dbg !29 {
+entry:
+  %c.addr = alloca i32, align 4
+  %b.addr = alloca i32, align 4
+  %a.addr = alloca i32, align 4
+  store i32 %c, i32* %c.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %c.addr, metadata !32, metadata !DIExpression()), !dbg !33
+  store i32 %b, i32* %b.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !34, metadata !DIExpression()), !dbg !35
+  store i32 %a, i32* %a.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !36, metadata !DIExpression()), !dbg !37
+  %0 = load i32, i32* %a.addr, align 4, !dbg !38
+  %1 = load i32, i32* %b.addr, align 4, !dbg !39
+  %add = add nsw i32 %0, %1, !dbg !40
+  %2 = load i32, i32* %c.addr, align 4, !dbg !41
+  %add1 = add nsw i32 %add, %2, !dbg !42
+  %3 = load i32, i32* @g, align 4, !dbg !43
+  %add2 = add nsw i32 %3, %add1, !dbg !43
+  store i32 %add2, i32* @g, align 4, !dbg !43
+  ret void, !dbg !44
+}
+
+; Function Attrs: noinline nounwind optnone
+define x86_fastcallcc void @"\01@fastcall1@4"(i32 inreg %a) #0 !dbg !45 {
+entry:
+  %a.addr = alloca i32, align 4
+  store i32 %a, i32* %a.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !47, metadata !DIExpression()), !dbg !48
+  %0 = load i32, i32* %a.addr, align 4, !dbg !49
+  %1 = load i32, i32* @g, align 4, !dbg !50
+  %add = add nsw i32 %1, %0, !dbg !50
+  store i32 %add, i32* @g, align 4, !dbg !50
+  ret void, !dbg !51
+}
+
+; Function Attrs: noinline nounwind optnone
+define x86_fastcallcc void @"\01@fastcall2@8"(i32 inreg %a, i32 inreg %b) #0 !dbg !52 {
+entry:
+  %b.addr = alloca i32, align 4
+  %a.addr = alloca i32, align 4
+  store i32 %b, i32* %b.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !54, metadata !DIExpression()), !dbg !55
+  store i32 %a, i32* %a.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !56, metadata !DIExpression()), !dbg !57
+  %0 = load i32, i32* %a.addr, align 4, !dbg !58
+  %1 = load i32, i32* %b.addr, align 4, !dbg !59
+  %add = add nsw i32 %0, %1, !dbg !60
+  %2 = load i32, i32* @g, align 4, !dbg !61
+  %add1 = add nsw i32 %2, %add, !dbg !61
+  store i32 %add1, i32* @g, align 4, !dbg !61
+  ret void, !dbg !62
+}
+
+; Function Attrs: noinline nounwind optnone
+define x86_fastcallcc void @"\01@fastcall3@12"(i32 inreg %a, i32 inreg %b, i32 %c) #0 !dbg !63 {
+entry:
+  %c.addr = alloca i32, align 4
+  %b.addr = alloca i32, align 4
+  %a.addr = alloca i32, align 4
+  store i32 %c, i32* %c.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %c.addr, metadata !65, metadata !DIExpression()), !dbg !66
+  store i32 %b, i32* %b.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !67, metadata !DIExpression()), !dbg !68
+  store i32 %a, i32* %a.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !69, metadata !DIExpression()), !dbg !70
+  %0 = load i32, i32* %a.addr, align 4, !dbg !71
+  %1 = load i32, i32* %b.addr, align 4, !dbg !72
+  %add = add nsw i32 %0, %1, !dbg !73
+  %2 = load i32, i32* %c.addr, align 4, !dbg !74
+  %add1 = add nsw i32 %add, %2, !dbg !75
+  %3 = load i32, i32* @g, align 4, !dbg !76
+  %add2 = add nsw i32 %3, %add1, !dbg !76
+  store i32 %add2, i32* @g, align 4, !dbg !76
+  ret void, !dbg !77
+}
+
+; Function Attrs: noinline nounwind optnone
+define x86_stdcallcc void @"\01_stdcall1@4"(i32 %a) #0 !dbg !78 {
+entry:
+  %a.addr = alloca i32, align 4
+  store i32 %a, i32* %a.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !80, metadata !DIExpression()), !dbg !81
+  %0 = load i32, i32* %a.addr, align 4, !dbg !82
+  %1 = load i32, i32* @g, align 4, !dbg !83
+  %add = add nsw i32 %1, %0, !dbg !83
+  store i32 %add, i32* @g, align 4, !dbg !83
+  ret void, !dbg !84
+}
+
+; Function Attrs: noinline nounwind optnone
+define x86_stdcallcc void @"\01_stdcall2@8"(i32 %a, i32 %b) #0 !dbg !85 {
+entry:
+  %b.addr = alloca i32, align 4
+  %a.addr = alloca i32, align 4
+  store i32 %b, i32* %b.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !87, metadata !DIExpression()), !dbg !88
+  store i32 %a, i32* %a.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !89, metadata !DIExpression()), !dbg !90
+  %0 = load i32, i32* %a.addr, align 4, !dbg !91
+  %1 = load i32, i32* %b.addr, align 4, !dbg !92
+  %add = add nsw i32 %0, %1, !dbg !93
+  %2 = load i32, i32* @g, align 4, !dbg !94
+  %add1 = add nsw i32 %2, %add, !dbg !94
+  store i32 %add1, i32* @g, align 4, !dbg !94
+  ret void, !dbg !95
+}
+
+; Function Attrs: noinline nounwind optnone
+define x86_stdcallcc void @"\01_stdcall3@12"(i32 %a, i32 %b, i32 %c) #0 !dbg !96 {
+entry:
+  %c.addr = alloca i32, align 4
+  %b.addr = alloca i32, align 4
+  %a.addr = alloca i32, align 4
+  store i32 %c, i32* %c.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %c.addr, metadata !98, metadata !DIExpression()), !dbg !99
+  store i32 %b, i32* %b.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !100, metadata !DIExpression()), !dbg !101
+  store i32 %a, i32* %a.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !102, metadata !DIExpression()), !dbg !103
+  %0 = load i32, i32* %a.addr, align 4, !dbg !104
+  %1 = load i32, i32* %b.addr, align 4, !dbg !105
+  %add = add nsw i32 %0, %1, !dbg !106
+  %2 = load i32, i32* %c.addr, align 4, !dbg !107
+  %add1 = add nsw i32 %add, %2, !dbg !108
+  %3 = load i32, i32* @g, align 4, !dbg !109
+  %add2 = add nsw i32 %3, %add1, !dbg !109
+  store i32 %add2, i32* @g, align 4, !dbg !109
+  ret void, !dbg !110
+}
+
+; Function Attrs: noinline nounwind optnone
+define x86_thiscallcc void @"\01?thiscall1@Foo@@QAEXH@Z"(%struct.Foo* %this, i32 %a) #0 align 2 !dbg !111 {
+entry:
+  %a.addr = alloca i32, align 4
+  %this.addr = alloca %struct.Foo*, align 4
+  store i32 %a, i32* %a.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !124, metadata !DIExpression()), !dbg !125
+  store %struct.Foo* %this, %struct.Foo** %this.addr, align 4
+  call void @llvm.dbg.declare(metadata %struct.Foo** %this.addr, metadata !126, metadata !DIExpression()), !dbg !128
+  %this1 = load %struct.Foo*, %struct.Foo** %this.addr, align 4
+  %0 = load i32, i32* %a.addr, align 4, !dbg !129
+  %1 = load i32, i32* @g, align 4, !dbg !130
+  %add = add nsw i32 %1, %0, !dbg !130
+  store i32 %add, i32* @g, align 4, !dbg !130
+  ret void, !dbg !131
+}
+
+; Function Attrs: noinline nounwind optnone
+define x86_thiscallcc void @"\01?thiscall2@Foo@@QAEXHH@Z"(%struct.Foo* %this, i32 %a, i32 %b) #0 align 2 !dbg !132 {
+entry:
+  %b.addr = alloca i32, align 4
+  %a.addr = alloca i32, align 4
+  %this.addr = alloca %struct.Foo*, align 4
+  store i32 %b, i32* %b.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !133, metadata !DIExpression()), !dbg !134
+  store i32 %a, i32* %a.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !135, metadata !DIExpression()), !dbg !136
+  store %struct.Foo* %this, %struct.Foo** %this.addr, align 4
+  call void @llvm.dbg.declare(metadata %struct.Foo** %this.addr, metadata !137, metadata !DIExpression()), !dbg !138
+  %this1 = load %struct.Foo*, %struct.Foo** %this.addr, align 4
+  %0 = load i32, i32* %a.addr, align 4, !dbg !139
+  %1 = load i32, i32* %b.addr, align 4, !dbg !140
+  %add = add nsw i32 %0, %1, !dbg !141
+  %2 = load i32, i32* @g, align 4, !dbg !142
+  %add2 = add nsw i32 %2, %add, !dbg !142
+  store i32 %add2, i32* @g, align 4, !dbg !142
+  ret void, !dbg !143
+}
+
+; Function Attrs: noinline nounwind optnone
+define x86_thiscallcc void @"\01?thiscall3@Foo@@QAEXHHH@Z"(%struct.Foo* %this, i32 %a, i32 %b, i32 %c) #0 align 2 !dbg !144 {
+entry:
+  %c.addr = alloca i32, align 4
+  %b.addr = alloca i32, align 4
+  %a.addr = alloca i32, align 4
+  %this.addr = alloca %struct.Foo*, align 4
+  store i32 %c, i32* %c.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %c.addr, metadata !145, metadata !DIExpression()), !dbg !146
+  store i32 %b, i32* %b.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !147, metadata !DIExpression()), !dbg !148
+  store i32 %a, i32* %a.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !149, metadata !DIExpression()), !dbg !150
+  store %struct.Foo* %this, %struct.Foo** %this.addr, align 4
+  call void @llvm.dbg.declare(metadata %struct.Foo** %this.addr, metadata !151, metadata !DIExpression()), !dbg !152
+  %this1 = load %struct.Foo*, %struct.Foo** %this.addr, align 4
+  %0 = load i32, i32* %a.addr, align 4, !dbg !153
+  %1 = load i32, i32* %b.addr, align 4, !dbg !154
+  %add = add nsw i32 %0, %1, !dbg !155
+  %2 = load i32, i32* %c.addr, align 4, !dbg !156
+  %add2 = add nsw i32 %add, %2, !dbg !157
+  %3 = load i32, i32* @g, align 4, !dbg !158
+  %add3 = add nsw i32 %3, %add2, !dbg !158
+  store i32 %add3, i32* @g, align 4, !dbg !158
+  ret void, !dbg !159
+}
+
+attributes #0 = { noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone speculatable }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 6.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "t.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "0ce3e4edcf2f8511157da4edb99fcdf4")
+!2 = !{}
+!3 = !{i32 1, !"NumRegisterParameters", i32 0}
+!4 = !{i32 2, !"CodeView", i32 1}
+!5 = !{i32 2, !"Debug Info Version", i32 3}
+!6 = !{i32 1, !"wchar_size", i32 2}
+!7 = !{!"clang version 6.0.0 "}
+!8 = distinct !DISubprogram(name: "cdecl1", scope: !1, file: !1, line: 4, type: !9, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!9 = !DISubroutineType(types: !10)
+!10 = !{null, !11}
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 4, type: !11)
+!13 = !DILocation(line: 4, column: 17, scope: !8)
+!14 = !DILocation(line: 4, column: 27, scope: !8)
+!15 = !DILocation(line: 4, column: 24, scope: !8)
+!16 = !DILocation(line: 4, column: 30, scope: !8)
+!17 = distinct !DISubprogram(name: "cdecl2", scope: !1, file: !1, line: 5, type: !18, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!18 = !DISubroutineType(types: !19)
+!19 = !{null, !11, !11}
+!20 = !DILocalVariable(name: "b", arg: 2, scope: !17, file: !1, line: 5, type: !11)
+!21 = !DILocation(line: 5, column: 24, scope: !17)
+!22 = !DILocalVariable(name: "a", arg: 1, scope: !17, file: !1, line: 5, type: !11)
+!23 = !DILocation(line: 5, column: 17, scope: !17)
+!24 = !DILocation(line: 5, column: 34, scope: !17)
+!25 = !DILocation(line: 5, column: 38, scope: !17)
+!26 = !DILocation(line: 5, column: 36, scope: !17)
+!27 = !DILocation(line: 5, column: 31, scope: !17)
+!28 = !DILocation(line: 5, column: 41, scope: !17)
+!29 = distinct !DISubprogram(name: "cdecl3", scope: !1, file: !1, line: 6, type: !30, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!30 = !DISubroutineType(types: !31)
+!31 = !{null, !11, !11, !11}
+!32 = !DILocalVariable(name: "c", arg: 3, scope: !29, file: !1, line: 6, type: !11)
+!33 = !DILocation(line: 6, column: 31, scope: !29)
+!34 = !DILocalVariable(name: "b", arg: 2, scope: !29, file: !1, line: 6, type: !11)
+!35 = !DILocation(line: 6, column: 24, scope: !29)
+!36 = !DILocalVariable(name: "a", arg: 1, scope: !29, file: !1, line: 6, type: !11)
+!37 = !DILocation(line: 6, column: 17, scope: !29)
+!38 = !DILocation(line: 6, column: 41, scope: !29)
+!39 = !DILocation(line: 6, column: 45, scope: !29)
+!40 = !DILocation(line: 6, column: 43, scope: !29)
+!41 = !DILocation(line: 6, column: 49, scope: !29)
+!42 = !DILocation(line: 6, column: 47, scope: !29)
+!43 = !DILocation(line: 6, column: 38, scope: !29)
+!44 = !DILocation(line: 6, column: 52, scope: !29)
+!45 = distinct !DISubprogram(name: "fastcall1", linkageName: "\01@fastcall1@4", scope: !1, file: !1, line: 8, type: !46, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!46 = !DISubroutineType(cc: DW_CC_BORLAND_msfastcall, types: !10)
+!47 = !DILocalVariable(name: "a", arg: 1, scope: !45, file: !1, line: 8, type: !11)
+!48 = !DILocation(line: 8, column: 31, scope: !45)
+!49 = !DILocation(line: 8, column: 41, scope: !45)
+!50 = !DILocation(line: 8, column: 38, scope: !45)
+!51 = !DILocation(line: 8, column: 44, scope: !45)
+!52 = distinct !DISubprogram(name: "fastcall2", linkageName: "\01@fastcall2@8", scope: !1, file: !1, line: 9, type: !53, isLocal: false, isDefinition: true, scopeLine: 9, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!53 = !DISubroutineType(cc: DW_CC_BORLAND_msfastcall, types: !19)
+!54 = !DILocalVariable(name: "b", arg: 2, scope: !52, file: !1, line: 9, type: !11)
+!55 = !DILocation(line: 9, column: 38, scope: !52)
+!56 = !DILocalVariable(name: "a", arg: 1, scope: !52, file: !1, line: 9, type: !11)
+!57 = !DILocation(line: 9, column: 31, scope: !52)
+!58 = !DILocation(line: 9, column: 48, scope: !52)
+!59 = !DILocation(line: 9, column: 52, scope: !52)
+!60 = !DILocation(line: 9, column: 50, scope: !52)
+!61 = !DILocation(line: 9, column: 45, scope: !52)
+!62 = !DILocation(line: 9, column: 55, scope: !52)
+!63 = distinct !DISubprogram(name: "fastcall3", linkageName: "\01@fastcall3@12", scope: !1, file: !1, line: 10, type: !64, isLocal: false, isDefinition: true, scopeLine: 10, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!64 = !DISubroutineType(cc: DW_CC_BORLAND_msfastcall, types: !31)
+!65 = !DILocalVariable(name: "c", arg: 3, scope: !63, file: !1, line: 10, type: !11)
+!66 = !DILocation(line: 10, column: 45, scope: !63)
+!67 = !DILocalVariable(name: "b", arg: 2, scope: !63, file: !1, line: 10, type: !11)
+!68 = !DILocation(line: 10, column: 38, scope: !63)
+!69 = !DILocalVariable(name: "a", arg: 1, scope: !63, file: !1, line: 10, type: !11)
+!70 = !DILocation(line: 10, column: 31, scope: !63)
+!71 = !DILocation(line: 10, column: 55, scope: !63)
+!72 = !DILocation(line: 10, column: 59, scope: !63)
+!73 = !DILocation(line: 10, column: 57, scope: !63)
+!74 = !DILocation(line: 10, column: 63, scope: !63)
+!75 = !DILocation(line: 10, column: 61, scope: !63)
+!76 = !DILocation(line: 10, column: 52, scope: !63)
+!77 = !DILocation(line: 10, column: 66, scope: !63)
+!78 = distinct !DISubprogram(name: "stdcall1", linkageName: "\01_stdcall1@4", scope: !1, file: !1, line: 12, type: !79, isLocal: false, isDefinition: true, scopeLine: 12, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!79 = !DISubroutineType(cc: DW_CC_BORLAND_stdcall, types: !10)
+!80 = !DILocalVariable(name: "a", arg: 1, scope: !78, file: !1, line: 12, type: !11)
+!81 = !DILocation(line: 12, column: 29, scope: !78)
+!82 = !DILocation(line: 12, column: 39, scope: !78)
+!83 = !DILocation(line: 12, column: 36, scope: !78)
+!84 = !DILocation(line: 12, column: 42, scope: !78)
+!85 = distinct !DISubprogram(name: "stdcall2", linkageName: "\01_stdcall2@8", scope: !1, file: !1, line: 13, type: !86, isLocal: false, isDefinition: true, scopeLine: 13, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!86 = !DISubroutineType(cc: DW_CC_BORLAND_stdcall, types: !19)
+!87 = !DILocalVariable(name: "b", arg: 2, scope: !85, file: !1, line: 13, type: !11)
+!88 = !DILocation(line: 13, column: 36, scope: !85)
+!89 = !DILocalVariable(name: "a", arg: 1, scope: !85, file: !1, line: 13, type: !11)
+!90 = !DILocation(line: 13, column: 29, scope: !85)
+!91 = !DILocation(line: 13, column: 46, scope: !85)
+!92 = !DILocation(line: 13, column: 50, scope: !85)
+!93 = !DILocation(line: 13, column: 48, scope: !85)
+!94 = !DILocation(line: 13, column: 43, scope: !85)
+!95 = !DILocation(line: 13, column: 53, scope: !85)
+!96 = distinct !DISubprogram(name: "stdcall3", linkageName: "\01_stdcall3@12", scope: !1, file: !1, line: 14, type: !97, isLocal: false, isDefinition: true, scopeLine: 14, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!97 = !DISubroutineType(cc: DW_CC_BORLAND_stdcall, types: !31)
+!98 = !DILocalVariable(name: "c", arg: 3, scope: !96, file: !1, line: 14, type: !11)
+!99 = !DILocation(line: 14, column: 43, scope: !96)
+!100 = !DILocalVariable(name: "b", arg: 2, scope: !96, file: !1, line: 14, type: !11)
+!101 = !DILocation(line: 14, column: 36, scope: !96)
+!102 = !DILocalVariable(name: "a", arg: 1, scope: !96, file: !1, line: 14, type: !11)
+!103 = !DILocation(line: 14, column: 29, scope: !96)
+!104 = !DILocation(line: 14, column: 53, scope: !96)
+!105 = !DILocation(line: 14, column: 57, scope: !96)
+!106 = !DILocation(line: 14, column: 55, scope: !96)
+!107 = !DILocation(line: 14, column: 61, scope: !96)
+!108 = !DILocation(line: 14, column: 59, scope: !96)
+!109 = !DILocation(line: 14, column: 50, scope: !96)
+!110 = !DILocation(line: 14, column: 64, scope: !96)
+!111 = distinct !DISubprogram(name: "thiscall1", linkageName: "\01?thiscall1@Foo@@QAEXH@Z", scope: !112, file: !1, line: 23, type: !115, isLocal: false, isDefinition: true, scopeLine: 23, flags: DIFlagPrototyped, isOptimized: false, unit: !0, declaration: !114, variables: !2)
+!112 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", file: !1, line: 17, size: 8, elements: !113, identifier: ".?AUFoo@@")
+!113 = !{!114, !118, !121}
+!114 = !DISubprogram(name: "thiscall1", linkageName: "\01?thiscall1@Foo@@QAEXH@Z", scope: !112, file: !1, line: 18, type: !115, isLocal: false, isDefinition: false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false)
+!115 = !DISubroutineType(cc: DW_CC_BORLAND_thiscall, types: !116)
+!116 = !{null, !117, !11}
+!117 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !112, size: 32, flags: DIFlagArtificial | DIFlagObjectPointer)
+!118 = !DISubprogram(name: "thiscall2", linkageName: "\01?thiscall2@Foo@@QAEXHH@Z", scope: !112, file: !1, line: 19, type: !119, isLocal: false, isDefinition: false, scopeLine: 19, flags: DIFlagPrototyped, isOptimized: false)
+!119 = !DISubroutineType(cc: DW_CC_BORLAND_thiscall, types: !120)
+!120 = !{null, !117, !11, !11}
+!121 = !DISubprogram(name: "thiscall3", linkageName: "\01?thiscall3@Foo@@QAEXHHH@Z", scope: !112, file: !1, line: 20, type: !122, isLocal: false, isDefinition: false, scopeLine: 20, flags: DIFlagPrototyped, isOptimized: false)
+!122 = !DISubroutineType(cc: DW_CC_BORLAND_thiscall, types: !123)
+!123 = !{null, !117, !11, !11, !11}
+!124 = !DILocalVariable(name: "a", arg: 2, scope: !111, file: !1, line: 23, type: !11)
+!125 = !DILocation(line: 23, column: 25, scope: !111)
+!126 = !DILocalVariable(name: "this", arg: 1, scope: !111, type: !127, flags: DIFlagArtificial | DIFlagObjectPointer)
+!127 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !112, size: 32)
+!128 = !DILocation(line: 0, scope: !111)
+!129 = !DILocation(line: 23, column: 35, scope: !111)
+!130 = !DILocation(line: 23, column: 32, scope: !111)
+!131 = !DILocation(line: 23, column: 38, scope: !111)
+!132 = distinct !DISubprogram(name: "thiscall2", linkageName: "\01?thiscall2@Foo@@QAEXHH@Z", scope: !112, file: !1, line: 24, type: !119, isLocal: false, isDefinition: true, scopeLine: 24, flags: DIFlagPrototyped, isOptimized: false, unit: !0, declaration: !118, variables: !2)
+!133 = !DILocalVariable(name: "b", arg: 3, scope: !132, file: !1, line: 24, type: !11)
+!134 = !DILocation(line: 24, column: 32, scope: !132)
+!135 = !DILocalVariable(name: "a", arg: 2, scope: !132, file: !1, line: 24, type: !11)
+!136 = !DILocation(line: 24, column: 25, scope: !132)
+!137 = !DILocalVariable(name: "this", arg: 1, scope: !132, type: !127, flags: DIFlagArtificial | DIFlagObjectPointer)
+!138 = !DILocation(line: 0, scope: !132)
+!139 = !DILocation(line: 24, column: 42, scope: !132)
+!140 = !DILocation(line: 24, column: 46, scope: !132)
+!141 = !DILocation(line: 24, column: 44, scope: !132)
+!142 = !DILocation(line: 24, column: 39, scope: !132)
+!143 = !DILocation(line: 24, column: 49, scope: !132)
+!144 = distinct !DISubprogram(name: "thiscall3", linkageName: "\01?thiscall3@Foo@@QAEXHHH@Z", scope: !112, file: !1, line: 25, type: !122, isLocal: false, isDefinition: true, scopeLine: 25, flags: DIFlagPrototyped, isOptimized: false, unit: !0, declaration: !121, variables: !2)
+!145 = !DILocalVariable(name: "c", arg: 4, scope: !144, file: !1, line: 25, type: !11)
+!146 = !DILocation(line: 25, column: 39, scope: !144)
+!147 = !DILocalVariable(name: "b", arg: 3, scope: !144, file: !1, line: 25, type: !11)
+!148 = !DILocation(line: 25, column: 32, scope: !144)
+!149 = !DILocalVariable(name: "a", arg: 2, scope: !144, file: !1, line: 25, type: !11)
+!150 = !DILocation(line: 25, column: 25, scope: !144)
+!151 = !DILocalVariable(name: "this", arg: 1, scope: !144, type: !127, flags: DIFlagArtificial | DIFlagObjectPointer)
+!152 = !DILocation(line: 0, scope: !144)
+!153 = !DILocation(line: 25, column: 49, scope: !144)
+!154 = !DILocation(line: 25, column: 53, scope: !144)
+!155 = !DILocation(line: 25, column: 51, scope: !144)
+!156 = !DILocation(line: 25, column: 57, scope: !144)
+!157 = !DILocation(line: 25, column: 55, scope: !144)
+!158 = !DILocation(line: 25, column: 46, scope: !144)
+!159 = !DILocation(line: 25, column: 60, scope: !144)
Index: llvm/test/DebugInfo/COFF/fpo-csrs.ll
===================================================================
--- /dev/null
+++ llvm/test/DebugInfo/COFF/fpo-csrs.ll
@@ -0,0 +1,559 @@
+; RUN: llc < %s | FileCheck %s --check-prefix=ASM
+; RUN: llc -filetype=obj < %s | llvm-readobj -codeview | FileCheck %s --check-prefix=OBJ
+
+; C source:
+; int getval(void);
+; void usevals(int, ...);
+; int csr1() {
+;   int a = getval();
+;   usevals(a);
+;   usevals(a);
+;   return a;
+; }
+; int csr2() {
+;   int a = getval();
+;   int b = getval();
+;   usevals(a, b);
+;   usevals(a, b);
+;   return a;
+; }
+; int csr3() {
+;   int a = getval();
+;   int b = getval();
+;   int c = getval();
+;   usevals(a, b, c);
+;   usevals(a, b, c);
+;   return a;
+; }
+; int csr4() {
+;   int a = getval();
+;   int b = getval();
+;   int c = getval();
+;   int d = getval();
+;   usevals(a, b, c, d);
+;   usevals(a, b, c, d);
+;   return a;
+; }
+; int spill() {
+;   int a = getval();
+;   int b = getval();
+;   int c = getval();
+;   int d = getval();
+;   int e = getval();
+;   usevals(a, b, c, d, e);
+;   usevals(a, b, c, d, e);
+;   return a;
+; }
+
+; ModuleID = 't.c'
+source_filename = "t.c"
+target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+target triple = "i386-pc-windows-msvc19.11.25508"
+
+; Function Attrs: nounwind
+define i32 @csr1() local_unnamed_addr #0 !dbg !8 {
+entry:
+  %call = tail call i32 @getval() #3, !dbg !14
+  tail call void @llvm.dbg.value(metadata i32 %call, metadata !13, metadata !DIExpression()), !dbg !15
+  tail call void (i32, ...) @usevals(i32 %call) #3, !dbg !16
+  tail call void (i32, ...) @usevals(i32 %call) #3, !dbg !17
+  ret i32 %call, !dbg !18
+}
+
+; ASM-LABEL: _csr1:                                  # @csr1
+; ASM:         .cv_fpo_proc    _csr1
+; ASM:         pushl   %esi
+; ASM:         .cv_fpo_pushreg %esi
+; ASM:         .cv_fpo_endprologue
+; ASM:         #DEBUG_VALUE: csr1:a <- %ESI
+; ASM:         retl
+; ASM:         .cv_fpo_endproc
+
+; OBJ-LABEL: SubSectionType: FrameData (0xF5)
+; OBJ-NEXT: SubSectionSize:
+; OBJ-NEXT: LinkageName: _csr1
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT:   RvaStart: 0x0
+; OBJ-NEXT:   CodeSize: 0x1E
+; OBJ-NEXT:   LocalSize: 0x0
+; OBJ-NEXT:   ParamsSize: 0x0
+; OBJ-NEXT:   MaxStackSize: 0x0
+; OBJ-NEXT:   FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+; OBJ-NEXT:   PrologSize: 0x1
+; OBJ-NEXT:   SavedRegsSize: 0x0
+; OBJ-NEXT:   Flags [ (0x4)
+; OBJ-NEXT:     IsFunctionStart (0x4)
+; OBJ-NEXT:   ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT:   RvaStart: 0x1
+; OBJ-NEXT:   CodeSize: 0x1D
+; OBJ-NEXT:   LocalSize: 0x0
+; OBJ-NEXT:   ParamsSize: 0x0
+; OBJ-NEXT:   MaxStackSize: 0x0
+; OBJ-NEXT:   FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $esi $T0 4 - ^ =
+; OBJ-NEXT:   PrologSize: 0x0
+; OBJ-NEXT:   SavedRegsSize: 0x4
+; OBJ-NEXT:   Flags [ (0x0)
+; OBJ-NEXT:   ]
+; OBJ-NEXT: }
+; OBJ-NOT: FrameData
+
+declare i32 @getval() local_unnamed_addr #1
+
+declare void @usevals(i32, ...) local_unnamed_addr #1
+
+; Function Attrs: nounwind
+define i32 @csr2() local_unnamed_addr #0 !dbg !19 {
+entry:
+  %call = tail call i32 @getval() #3, !dbg !23
+  tail call void @llvm.dbg.value(metadata i32 %call, metadata !21, metadata !DIExpression()), !dbg !24
+  %call1 = tail call i32 @getval() #3, !dbg !25
+  tail call void @llvm.dbg.value(metadata i32 %call1, metadata !22, metadata !DIExpression()), !dbg !26
+  tail call void (i32, ...) @usevals(i32 %call, i32 %call1) #3, !dbg !27
+  tail call void (i32, ...) @usevals(i32 %call, i32 %call1) #3, !dbg !28
+  ret i32 %call, !dbg !29
+}
+
+; ASM-LABEL: _csr2:                                  # @csr2
+; ASM:         .cv_fpo_proc    _csr2
+; ASM:         pushl   %edi
+; ASM:         .cv_fpo_pushreg %edi
+; ASM:         pushl   %esi
+; ASM:         .cv_fpo_pushreg %esi
+; ASM:         .cv_fpo_endprologue
+; ASM:         #DEBUG_VALUE: csr2:a <- %ESI
+; ASM:         #DEBUG_VALUE: csr2:b <- %EDI
+; ASM:         retl
+; ASM:         .cv_fpo_endproc
+
+; OBJ-LABEL: SubSectionType: FrameData (0xF5)
+; OBJ-NEXT: SubSectionSize:
+; OBJ-NEXT: LinkageName: _csr2
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT:   RvaStart: 0x0
+; OBJ-NEXT:   CodeSize: 0x29
+; OBJ-NEXT:   LocalSize: 0x0
+; OBJ-NEXT:   ParamsSize: 0x0
+; OBJ-NEXT:   MaxStackSize: 0x0
+; OBJ-NEXT:   FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+; OBJ-NEXT:   PrologSize: 0x2
+; OBJ-NEXT:   SavedRegsSize: 0x0
+; OBJ-NEXT:   Flags [ (0x4)
+; OBJ-NEXT:     IsFunctionStart (0x4)
+; OBJ-NEXT:   ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT:   RvaStart: 0x1
+; OBJ-NEXT:   CodeSize: 0x28
+; OBJ-NEXT:   LocalSize: 0x0
+; OBJ-NEXT:   ParamsSize: 0x0
+; OBJ-NEXT:   MaxStackSize: 0x0
+; OBJ-NEXT:   FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $edi $T0 4 - ^ =
+; OBJ-NEXT:   PrologSize: 0x1
+; OBJ-NEXT:   SavedRegsSize: 0x4
+; OBJ-NEXT:   Flags [ (0x0)
+; OBJ-NEXT:   ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT:   RvaStart: 0x2
+; OBJ-NEXT:   CodeSize: 0x27
+; OBJ-NEXT:   LocalSize: 0x0
+; OBJ-NEXT:   ParamsSize: 0x0
+; OBJ-NEXT:   MaxStackSize: 0x0
+; OBJ-NEXT:   FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $edi $T0 4 - ^ = $esi $T0 8 - ^ =
+; OBJ-NEXT:   PrologSize: 0x0
+; OBJ-NEXT:   SavedRegsSize: 0x8
+; OBJ-NEXT:   Flags [ (0x0)
+; OBJ-NEXT:   ]
+; OBJ-NEXT: }
+; OBJ-NOT: FrameData
+
+; Function Attrs: nounwind
+define i32 @csr3() local_unnamed_addr #0 !dbg !30 {
+entry:
+  %call = tail call i32 @getval() #3, !dbg !35
+  tail call void @llvm.dbg.value(metadata i32 %call, metadata !32, metadata !DIExpression()), !dbg !36
+  %call1 = tail call i32 @getval() #3, !dbg !37
+  tail call void @llvm.dbg.value(metadata i32 %call1, metadata !33, metadata !DIExpression()), !dbg !38
+  %call2 = tail call i32 @getval() #3, !dbg !39
+  tail call void @llvm.dbg.value(metadata i32 %call2, metadata !34, metadata !DIExpression()), !dbg !40
+  tail call void (i32, ...) @usevals(i32 %call, i32 %call1, i32 %call2) #3, !dbg !41
+  tail call void (i32, ...) @usevals(i32 %call, i32 %call1, i32 %call2) #3, !dbg !42
+  ret i32 %call, !dbg !43
+}
+
+; ASM-LABEL: _csr3:                                  # @csr3
+; ASM:         .cv_fpo_proc    _csr3
+; ASM:         pushl   %ebx
+; ASM:         .cv_fpo_pushreg %ebx
+; ASM:         pushl   %edi
+; ASM:         .cv_fpo_pushreg %edi
+; ASM:         pushl   %esi
+; ASM:         .cv_fpo_pushreg %esi
+; ASM:         .cv_fpo_endprologue
+; ASM:         #DEBUG_VALUE: csr3:a <- %ESI
+; ASM:         #DEBUG_VALUE: csr3:b <- %EDI
+; ASM:         #DEBUG_VALUE: csr3:c <- %EBX
+; ASM:         retl
+; ASM:         .cv_fpo_endproc
+
+; OBJ-LABEL: SubSectionType: FrameData (0xF5)
+; OBJ-NEXT: SubSectionSize:
+; OBJ-NEXT: LinkageName: _csr3
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT:   RvaStart: 0x0
+; OBJ-NEXT:   CodeSize: 0x34
+; OBJ-NEXT:   LocalSize: 0x0
+; OBJ-NEXT:   ParamsSize: 0x0
+; OBJ-NEXT:   MaxStackSize: 0x0
+; OBJ-NEXT:   FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+; OBJ-NEXT:   PrologSize: 0x3
+; OBJ-NEXT:   SavedRegsSize: 0x0
+; OBJ-NEXT:   Flags [ (0x4)
+; OBJ-NEXT:     IsFunctionStart (0x4)
+; OBJ-NEXT:   ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT:   RvaStart: 0x1
+; OBJ-NEXT:   CodeSize: 0x33
+; OBJ-NEXT:   LocalSize: 0x0
+; OBJ-NEXT:   ParamsSize: 0x0
+; OBJ-NEXT:   MaxStackSize: 0x0
+; OBJ-NEXT:   FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebx $T0 4 - ^ =
+; OBJ-NEXT:   PrologSize: 0x2
+; OBJ-NEXT:   SavedRegsSize: 0x4
+; OBJ-NEXT:   Flags [ (0x0)
+; OBJ-NEXT:   ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT:   RvaStart: 0x2
+; OBJ-NEXT:   CodeSize: 0x32
+; OBJ-NEXT:   LocalSize: 0x0
+; OBJ-NEXT:   ParamsSize: 0x0
+; OBJ-NEXT:   MaxStackSize: 0x0
+; OBJ-NEXT:   FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebx $T0 4 - ^ = $edi $T0 8 - ^ =
+; OBJ-NEXT:   PrologSize: 0x1
+; OBJ-NEXT:   SavedRegsSize: 0x8
+; OBJ-NEXT:   Flags [ (0x0)
+; OBJ-NEXT:   ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT:   RvaStart: 0x3
+; OBJ-NEXT:   CodeSize: 0x31
+; OBJ-NEXT:   LocalSize: 0x0
+; OBJ-NEXT:   ParamsSize: 0x0
+; OBJ-NEXT:   MaxStackSize: 0x0
+; OBJ-NEXT:   FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebx $T0 4 - ^ = $edi $T0 8 - ^ = $esi $T0 12 - ^ =
+; OBJ-NEXT:   PrologSize: 0x0
+; OBJ-NEXT:   SavedRegsSize: 0xC
+; OBJ-NEXT:   Flags [ (0x0)
+; OBJ-NEXT:   ]
+; OBJ-NEXT: }
+; OBJ-NOT: FrameData
+
+; Function Attrs: nounwind
+define i32 @csr4() local_unnamed_addr #0 !dbg !44 {
+entry:
+  %call = tail call i32 @getval() #3, !dbg !50
+  tail call void @llvm.dbg.value(metadata i32 %call, metadata !46, metadata !DIExpression()), !dbg !51
+  %call1 = tail call i32 @getval() #3, !dbg !52
+  tail call void @llvm.dbg.value(metadata i32 %call1, metadata !47, metadata !DIExpression()), !dbg !53
+  %call2 = tail call i32 @getval() #3, !dbg !54
+  tail call void @llvm.dbg.value(metadata i32 %call2, metadata !48, metadata !DIExpression()), !dbg !55
+  %call3 = tail call i32 @getval() #3, !dbg !56
+  tail call void @llvm.dbg.value(metadata i32 %call3, metadata !49, metadata !DIExpression()), !dbg !57
+  tail call void (i32, ...) @usevals(i32 %call, i32 %call1, i32 %call2, i32 %call3) #3, !dbg !58
+  tail call void (i32, ...) @usevals(i32 %call, i32 %call1, i32 %call2, i32 %call3) #3, !dbg !59
+  ret i32 %call, !dbg !60
+}
+
+; ASM-LABEL: _csr4:                                  # @csr4
+; ASM:         .cv_fpo_proc    _csr4
+; ASM:         pushl   %ebp
+; ASM:         .cv_fpo_pushreg %ebp
+; ASM:         pushl   %ebx
+; ASM:         .cv_fpo_pushreg %ebx
+; ASM:         pushl   %edi
+; ASM:         .cv_fpo_pushreg %edi
+; ASM:         pushl   %esi
+; ASM:         .cv_fpo_pushreg %esi
+; ASM:         .cv_fpo_endprologue
+; ASM:         #DEBUG_VALUE: csr4:a <- %ESI
+; ASM:         #DEBUG_VALUE: csr4:b <- %EDI
+; ASM:         #DEBUG_VALUE: csr4:c <- %EBX
+; ASM:         #DEBUG_VALUE: csr4:d <- %EBP
+; ASM:         retl
+; ASM:         .cv_fpo_endproc
+
+; OBJ-LABEL: SubSectionType: FrameData (0xF5)
+; OBJ-NEXT: SubSectionSize:
+; OBJ-NEXT: LinkageName: _csr4
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT:   RvaStart: 0x0
+; OBJ-NEXT:   CodeSize: 0x3F
+; OBJ-NEXT:   LocalSize: 0x0
+; OBJ-NEXT:   ParamsSize: 0x0
+; OBJ-NEXT:   MaxStackSize: 0x0
+; OBJ-NEXT:   FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+; OBJ-NEXT:   PrologSize: 0x4
+; OBJ-NEXT:   SavedRegsSize: 0x0
+; OBJ-NEXT:   Flags [ (0x4)
+; OBJ-NEXT:     IsFunctionStart (0x4)
+; OBJ-NEXT:   ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT:   RvaStart: 0x1
+; OBJ-NEXT:   CodeSize: 0x3E
+; OBJ-NEXT:   LocalSize: 0x0
+; OBJ-NEXT:   ParamsSize: 0x0
+; OBJ-NEXT:   MaxStackSize: 0x0
+; OBJ-NEXT:   FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
+; OBJ-NEXT:   PrologSize: 0x3
+; OBJ-NEXT:   SavedRegsSize: 0x4
+; OBJ-NEXT:   Flags [ (0x0)
+; OBJ-NEXT:   ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT:   RvaStart: 0x2
+; OBJ-NEXT:   CodeSize: 0x3D
+; OBJ-NEXT:   LocalSize: 0x0
+; OBJ-NEXT:   ParamsSize: 0x0
+; OBJ-NEXT:   MaxStackSize: 0x0
+; OBJ-NEXT:   FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ =
+; OBJ-NEXT:   PrologSize: 0x2
+; OBJ-NEXT:   SavedRegsSize: 0x8
+; OBJ-NEXT:   Flags [ (0x0)
+; OBJ-NEXT:   ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT:   RvaStart: 0x3
+; OBJ-NEXT:   CodeSize: 0x3C
+; OBJ-NEXT:   LocalSize: 0x0
+; OBJ-NEXT:   ParamsSize: 0x0
+; OBJ-NEXT:   MaxStackSize: 0x0
+; OBJ-NEXT:   FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ =
+; OBJ-NEXT:   PrologSize: 0x1
+; OBJ-NEXT:   SavedRegsSize: 0xC
+; OBJ-NEXT:   Flags [ (0x0)
+; OBJ-NEXT:   ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT:   RvaStart: 0x4
+; OBJ-NEXT:   CodeSize: 0x3B
+; OBJ-NEXT:   LocalSize: 0x0
+; OBJ-NEXT:   ParamsSize: 0x0
+; OBJ-NEXT:   MaxStackSize: 0x0
+; OBJ-NEXT:   FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ = $esi $T0 16 - ^ =
+; OBJ-NEXT:   PrologSize: 0x0
+; OBJ-NEXT:   SavedRegsSize: 0x10
+; OBJ-NEXT:   Flags [ (0x0)
+; OBJ-NEXT:   ]
+; OBJ-NEXT: }
+; OBJ-NOT: FrameData
+
+; Function Attrs: nounwind
+define i32 @spill() local_unnamed_addr #0 !dbg !61 {
+entry:
+  %call = tail call i32 @getval() #3, !dbg !68
+  tail call void @llvm.dbg.value(metadata i32 %call, metadata !63, metadata !DIExpression()), !dbg !69
+  %call1 = tail call i32 @getval() #3, !dbg !70
+  tail call void @llvm.dbg.value(metadata i32 %call1, metadata !64, metadata !DIExpression()), !dbg !71
+  %call2 = tail call i32 @getval() #3, !dbg !72
+  tail call void @llvm.dbg.value(metadata i32 %call2, metadata !65, metadata !DIExpression()), !dbg !73
+  %call3 = tail call i32 @getval() #3, !dbg !74
+  tail call void @llvm.dbg.value(metadata i32 %call3, metadata !66, metadata !DIExpression()), !dbg !75
+  %call4 = tail call i32 @getval() #3, !dbg !76
+  tail call void @llvm.dbg.value(metadata i32 %call4, metadata !67, metadata !DIExpression()), !dbg !77
+  tail call void (i32, ...) @usevals(i32 %call, i32 %call1, i32 %call2, i32 %call3, i32 %call4) #3, !dbg !78
+  tail call void (i32, ...) @usevals(i32 %call, i32 %call1, i32 %call2, i32 %call3, i32 %call4) #3, !dbg !79
+  ret i32 %call, !dbg !80
+}
+
+; ASM-LABEL: _spill:                                  # @spill
+; ASM:         .cv_fpo_proc    _spill
+; ASM:         pushl   %ebp
+; ASM:         .cv_fpo_pushreg %ebp
+; ASM:         pushl   %ebx
+; ASM:         .cv_fpo_pushreg %ebx
+; ASM:         pushl   %edi
+; ASM:         .cv_fpo_pushreg %edi
+; ASM:         pushl   %esi
+; ASM:         .cv_fpo_pushreg %esi
+; ASM:         subl    $8, %esp
+; ASM:         .cv_fpo_stackalloc 8
+; ASM:         .cv_fpo_endprologue
+; ASM:         retl
+; ASM:         .cv_fpo_endproc
+
+; OBJ-LABEL: SubSectionType: FrameData (0xF5)
+; OBJ-NEXT: SubSectionSize:
+; OBJ-NEXT: LinkageName: _spill
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT:   RvaStart: 0x0
+; OBJ-NEXT:   CodeSize: 0x5A
+; OBJ-NEXT:   LocalSize: 0x0
+; OBJ-NEXT:   ParamsSize: 0x0
+; OBJ-NEXT:   MaxStackSize: 0x0
+; OBJ-NEXT:   FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+; OBJ-NEXT:   PrologSize: 0x7
+; OBJ-NEXT:   SavedRegsSize: 0x0
+; OBJ-NEXT:   Flags [ (0x4)
+; OBJ-NEXT:     IsFunctionStart (0x4)
+; OBJ-NEXT:   ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT:   RvaStart: 0x1
+; OBJ-NEXT:   CodeSize: 0x59
+; OBJ-NEXT:   LocalSize: 0x0
+; OBJ-NEXT:   ParamsSize: 0x0
+; OBJ-NEXT:   MaxStackSize: 0x0
+; OBJ-NEXT:   FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
+; OBJ-NEXT:   PrologSize: 0x6
+; OBJ-NEXT:   SavedRegsSize: 0x4
+; OBJ-NEXT:   Flags [ (0x0)
+; OBJ-NEXT:   ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT:   RvaStart: 0x2
+; OBJ-NEXT:   CodeSize: 0x58
+; OBJ-NEXT:   LocalSize: 0x0
+; OBJ-NEXT:   ParamsSize: 0x0
+; OBJ-NEXT:   MaxStackSize: 0x0
+; OBJ-NEXT:   FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ =
+; OBJ-NEXT:   PrologSize: 0x5
+; OBJ-NEXT:   SavedRegsSize: 0x8
+; OBJ-NEXT:   Flags [ (0x0)
+; OBJ-NEXT:   ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT:   RvaStart: 0x3
+; OBJ-NEXT:   CodeSize: 0x57
+; OBJ-NEXT:   LocalSize: 0x0
+; OBJ-NEXT:   ParamsSize: 0x0
+; OBJ-NEXT:   MaxStackSize: 0x0
+; OBJ-NEXT:   FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ =
+; OBJ-NEXT:   PrologSize: 0x4
+; OBJ-NEXT:   SavedRegsSize: 0xC
+; OBJ-NEXT:   Flags [ (0x0)
+; OBJ-NEXT:   ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT:   RvaStart: 0x4
+; OBJ-NEXT:   CodeSize: 0x56
+; OBJ-NEXT:   LocalSize: 0x0
+; OBJ-NEXT:   ParamsSize: 0x0
+; OBJ-NEXT:   MaxStackSize: 0x0
+; OBJ-NEXT:   FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ = $esi $T0 16 - ^ =
+; OBJ-NEXT:   PrologSize: 0x3
+; OBJ-NEXT:   SavedRegsSize: 0x10
+; OBJ-NEXT:   Flags [ (0x0)
+; OBJ-NEXT:   ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT:   RvaStart: 0x7
+; OBJ-NEXT:   CodeSize: 0x53
+; OBJ-NEXT:   LocalSize: 0x8
+; OBJ-NEXT:   ParamsSize: 0x0
+; OBJ-NEXT:   MaxStackSize: 0x0
+; OBJ-NEXT:   FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ = $esi $T0 16 - ^ =
+; OBJ-NEXT:   PrologSize: 0x0
+; OBJ-NEXT:   SavedRegsSize: 0x10
+; OBJ-NEXT:   Flags [ (0x0)
+; OBJ-NEXT:   ]
+; OBJ-NEXT: }
+; OBJ-NOT: FrameData
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone speculatable }
+attributes #3 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "t.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "0b1c85f8a0bfb41380df1fcaeadde306")
+!2 = !{}
+!3 = !{i32 1, !"NumRegisterParameters", i32 0}
+!4 = !{i32 2, !"CodeView", i32 1}
+!5 = !{i32 2, !"Debug Info Version", i32 3}
+!6 = !{i32 1, !"wchar_size", i32 2}
+!7 = !{!"clang version 6.0.0 "}
+!8 = distinct !DISubprogram(name: "csr1", scope: !1, file: !1, line: 3, type: !9, isLocal: false, isDefinition: true, scopeLine: 3, isOptimized: true, unit: !0, variables: !12)
+!9 = !DISubroutineType(types: !10)
+!10 = !{!11}
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !{!13}
+!13 = !DILocalVariable(name: "a", scope: !8, file: !1, line: 4, type: !11)
+!14 = !DILocation(line: 4, column: 11, scope: !8)
+!15 = !DILocation(line: 4, column: 7, scope: !8)
+!16 = !DILocation(line: 5, column: 3, scope: !8)
+!17 = !DILocation(line: 6, column: 3, scope: !8)
+!18 = !DILocation(line: 7, column: 3, scope: !8)
+!19 = distinct !DISubprogram(name: "csr2", scope: !1, file: !1, line: 9, type: !9, isLocal: false, isDefinition: true, scopeLine: 9, isOptimized: true, unit: !0, variables: !20)
+!20 = !{!21, !22}
+!21 = !DILocalVariable(name: "a", scope: !19, file: !1, line: 10, type: !11)
+!22 = !DILocalVariable(name: "b", scope: !19, file: !1, line: 11, type: !11)
+!23 = !DILocation(line: 10, column: 11, scope: !19)
+!24 = !DILocation(line: 10, column: 7, scope: !19)
+!25 = !DILocation(line: 11, column: 11, scope: !19)
+!26 = !DILocation(line: 11, column: 7, scope: !19)
+!27 = !DILocation(line: 12, column: 3, scope: !19)
+!28 = !DILocation(line: 13, column: 3, scope: !19)
+!29 = !DILocation(line: 14, column: 3, scope: !19)
+!30 = distinct !DISubprogram(name: "csr3", scope: !1, file: !1, line: 16, type: !9, isLocal: false, isDefinition: true, scopeLine: 16, isOptimized: true, unit: !0, variables: !31)
+!31 = !{!32, !33, !34}
+!32 = !DILocalVariable(name: "a", scope: !30, file: !1, line: 17, type: !11)
+!33 = !DILocalVariable(name: "b", scope: !30, file: !1, line: 18, type: !11)
+!34 = !DILocalVariable(name: "c", scope: !30, file: !1, line: 19, type: !11)
+!35 = !DILocation(line: 17, column: 11, scope: !30)
+!36 = !DILocation(line: 17, column: 7, scope: !30)
+!37 = !DILocation(line: 18, column: 11, scope: !30)
+!38 = !DILocation(line: 18, column: 7, scope: !30)
+!39 = !DILocation(line: 19, column: 11, scope: !30)
+!40 = !DILocation(line: 19, column: 7, scope: !30)
+!41 = !DILocation(line: 20, column: 3, scope: !30)
+!42 = !DILocation(line: 21, column: 3, scope: !30)
+!43 = !DILocation(line: 22, column: 3, scope: !30)
+!44 = distinct !DISubprogram(name: "csr4", scope: !1, file: !1, line: 24, type: !9, isLocal: false, isDefinition: true, scopeLine: 24, isOptimized: true, unit: !0, variables: !45)
+!45 = !{!46, !47, !48, !49}
+!46 = !DILocalVariable(name: "a", scope: !44, file: !1, line: 25, type: !11)
+!47 = !DILocalVariable(name: "b", scope: !44, file: !1, line: 26, type: !11)
+!48 = !DILocalVariable(name: "c", scope: !44, file: !1, line: 27, type: !11)
+!49 = !DILocalVariable(name: "d", scope: !44, file: !1, line: 28, type: !11)
+!50 = !DILocation(line: 25, column: 11, scope: !44)
+!51 = !DILocation(line: 25, column: 7, scope: !44)
+!52 = !DILocation(line: 26, column: 11, scope: !44)
+!53 = !DILocation(line: 26, column: 7, scope: !44)
+!54 = !DILocation(line: 27, column: 11, scope: !44)
+!55 = !DILocation(line: 27, column: 7, scope: !44)
+!56 = !DILocation(line: 28, column: 11, scope: !44)
+!57 = !DILocation(line: 28, column: 7, scope: !44)
+!58 = !DILocation(line: 29, column: 3, scope: !44)
+!59 = !DILocation(line: 30, column: 3, scope: !44)
+!60 = !DILocation(line: 31, column: 3, scope: !44)
+!61 = distinct !DISubprogram(name: "spill", scope: !1, file: !1, line: 33, type: !9, isLocal: false, isDefinition: true, scopeLine: 33, isOptimized: true, unit: !0, variables: !62)
+!62 = !{!63, !64, !65, !66, !67}
+!63 = !DILocalVariable(name: "a", scope: !61, file: !1, line: 34, type: !11)
+!64 = !DILocalVariable(name: "b", scope: !61, file: !1, line: 35, type: !11)
+!65 = !DILocalVariable(name: "c", scope: !61, file: !1, line: 36, type: !11)
+!66 = !DILocalVariable(name: "d", scope: !61, file: !1, line: 37, type: !11)
+!67 = !DILocalVariable(name: "e", scope: !61, file: !1, line: 38, type: !11)
+!68 = !DILocation(line: 34, column: 11, scope: !61)
+!69 = !DILocation(line: 34, column: 7, scope: !61)
+!70 = !DILocation(line: 35, column: 11, scope: !61)
+!71 = !DILocation(line: 35, column: 7, scope: !61)
+!72 = !DILocation(line: 36, column: 11, scope: !61)
+!73 = !DILocation(line: 36, column: 7, scope: !61)
+!74 = !DILocation(line: 37, column: 11, scope: !61)
+!75 = !DILocation(line: 37, column: 7, scope: !61)
+!76 = !DILocation(line: 38, column: 11, scope: !61)
+!77 = !DILocation(line: 38, column: 7, scope: !61)
+!78 = !DILocation(line: 39, column: 3, scope: !61)
+!79 = !DILocation(line: 40, column: 3, scope: !61)
+!80 = !DILocation(line: 41, column: 3, scope: !61)
Index: llvm/test/DebugInfo/COFF/fpo-realign-alloca.ll
===================================================================
--- /dev/null
+++ llvm/test/DebugInfo/COFF/fpo-realign-alloca.ll
@@ -0,0 +1,110 @@
+; RUN: llc < %s | FileCheck %s
+
+; C source:
+; void usethings(double *, void *p);
+; int realign_and_alloca(int n) {
+;   double d = 0;
+;   void *p = __builtin_alloca(n);
+;   usethings(&d, p);
+;   return 0;
+; }
+
+; CHECK: _realign_and_alloca:                    # @realign_and_alloca
+; CHECK:         .cv_fpo_proc    _realign_and_alloca 4
+; CHECK:         pushl   %ebp
+; CHECK:         .cv_fpo_pushreg %ebp
+; CHECK:         movl    %esp, %ebp
+; CHECK:         .cv_fpo_setframe        %ebp
+; CHECK:         pushl   %esi
+; CHECK:         .cv_fpo_pushreg %esi
+;       We don't seem to need to describe this AND because at this point CSRs
+;       are stored relative to EBP, but it's suspicious.
+; CHECK:         andl    $-16, %esp
+; CHECK:         subl    $32, %esp
+; CHECK:         .cv_fpo_stackalloc      32
+; CHECK:         .cv_fpo_endprologue
+; CHECK:         movl    %esp, %esi
+; CHECK:         leal    8(%esi),
+; CHECK:         calll   _usethings
+; CHECK:         addl    $8, %esp
+; CHECK:         xorl    %eax, %eax
+; CHECK:         leal    -4(%ebp), %esp
+; CHECK:         popl    %esi
+; CHECK:         popl    %ebp
+; CHECK:         retl
+; CHECK:         .cv_fpo_endproc
+
+
+; ModuleID = 't.c'
+source_filename = "t.c"
+target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+target triple = "i386-pc-windows-msvc19.11.25508"
+
+; Function Attrs: nounwind
+define i32 @realign_and_alloca(i32 %n) local_unnamed_addr #0 !dbg !8 {
+entry:
+  %d = alloca double, align 8
+  tail call void @llvm.dbg.value(metadata i32 %n, metadata !13, metadata !DIExpression()), !dbg !18
+  %0 = bitcast double* %d to i8*, !dbg !19
+  call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %0) #4, !dbg !19
+  tail call void @llvm.dbg.value(metadata double 0.000000e+00, metadata !14, metadata !DIExpression()), !dbg !20
+  store double 0.000000e+00, double* %d, align 8, !dbg !20, !tbaa !21
+  %1 = alloca i8, i32 %n, align 16, !dbg !25
+  tail call void @llvm.dbg.value(metadata i8* %1, metadata !16, metadata !DIExpression()), !dbg !26
+  tail call void @llvm.dbg.value(metadata double* %d, metadata !14, metadata !DIExpression()), !dbg !20
+  call void @usethings(double* nonnull %d, i8* nonnull %1) #4, !dbg !27
+  call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %0) #4, !dbg !28
+  ret i32 0, !dbg !29
+}
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1
+
+declare void @usethings(double*, i8*) local_unnamed_addr #2
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { argmemonly nounwind }
+attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #3 = { nounwind readnone speculatable }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "t.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "cfdc2deff5dc50f95e287f877660d4dd")
+!2 = !{}
+!3 = !{i32 1, !"NumRegisterParameters", i32 0}
+!4 = !{i32 2, !"CodeView", i32 1}
+!5 = !{i32 2, !"Debug Info Version", i32 3}
+!6 = !{i32 1, !"wchar_size", i32 2}
+!7 = !{!"clang version 6.0.0 "}
+!8 = distinct !DISubprogram(name: "realign_and_alloca", scope: !1, file: !1, line: 2, type: !9, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !12)
+!9 = !DISubroutineType(types: !10)
+!10 = !{!11, !11}
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !{!13, !14, !16}
+!13 = !DILocalVariable(name: "n", arg: 1, scope: !8, file: !1, line: 2, type: !11)
+!14 = !DILocalVariable(name: "d", scope: !8, file: !1, line: 3, type: !15)
+!15 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float)
+!16 = !DILocalVariable(name: "p", scope: !8, file: !1, line: 4, type: !17)
+!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 32)
+!18 = !DILocation(line: 2, column: 28, scope: !8)
+!19 = !DILocation(line: 3, column: 3, scope: !8)
+!20 = !DILocation(line: 3, column: 10, scope: !8)
+!21 = !{!22, !22, i64 0}
+!22 = !{!"double", !23, i64 0}
+!23 = !{!"omnipotent char", !24, i64 0}
+!24 = !{!"Simple C/C++ TBAA"}
+!25 = !DILocation(line: 4, column: 13, scope: !8)
+!26 = !DILocation(line: 4, column: 9, scope: !8)
+!27 = !DILocation(line: 5, column: 3, scope: !8)
+!28 = !DILocation(line: 7, column: 1, scope: !8)
+!29 = !DILocation(line: 6, column: 3, scope: !8)
Index: llvm/test/DebugInfo/COFF/fpo-shrink-wrap.ll
===================================================================
--- /dev/null
+++ llvm/test/DebugInfo/COFF/fpo-shrink-wrap.ll
@@ -0,0 +1,154 @@
+; RUN: llc -enable-shrink-wrap=true < %s | FileCheck %s --check-prefix=ASM
+; RUN: llc -enable-shrink-wrap=true -filetype=obj < %s | llvm-readobj -codeview | FileCheck %s --check-prefix=OBJ
+
+; C source:
+; int doSomething(int*);
+; int __fastcall shrink_wrap_basic(int a, int b, int c, int d) {
+;   if (a < b)
+;     return a;
+;   for (int i = c; i < d; ++i)
+;     doSomething(&c);
+;   return doSomething(&c);
+; }
+
+; ASM: @shrink_wrap_basic@16:                  # @"\01@shrink_wrap_basic@16"
+; ASM:         .cv_fpo_proc    @shrink_wrap_basic@16 8
+; ASM:         .cv_loc 0 1 3 9                 # t.c:3:9
+; ASM:         movl    %ecx, %eax
+; ASM:         cmpl    %edx, %eax
+; ASM:         jl      [[EPILOGUE:LBB0_[0-9]+]]
+
+; ASM:         pushl   %ebx
+; ASM:         .cv_fpo_pushreg %ebx
+; ASM:         pushl   %edi
+; ASM:         .cv_fpo_pushreg %edi
+; ASM:         pushl   %esi
+; ASM:         .cv_fpo_pushreg %esi
+; ASM:         .cv_fpo_endprologue
+
+; ASM:         calll   _doSomething
+
+; ASM:         popl    %esi
+; ASM:         popl    %edi
+; ASM:         popl    %ebx
+; ASM: [[EPILOGUE]]:                                 # %return
+; ASM:         retl    $8
+; ASM: Ltmp11:
+; ASM:         .cv_fpo_endproc
+
+; Note how RvaStart advances 7 bytes to skip the shrink-wrapped portion.
+; OBJ: SubSectionType: FrameData (0xF5)
+; OBJ:    FrameData {
+; OBJ:      RvaStart: 0x0
+; OBJ:      CodeSize: 0x34
+; OBJ:      FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+; OBJ:      PrologSize: 0x9
+; OBJ:    }
+; OBJ:    FrameData {
+; OBJ:      RvaStart: 0x7
+; OBJ:      CodeSize: 0x2D
+; OBJ:      FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebx $T0 4 - ^ =
+; OBJ:      PrologSize: 0x2
+; OBJ:    }
+; OBJ:    FrameData {
+; OBJ:      RvaStart: 0x8
+; OBJ:      CodeSize: 0x2C
+; OBJ:      FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebx $T0 4 - ^ = $edi $T0 8 - ^ =
+; OBJ:      PrologSize: 0x1
+; OBJ:    }
+; OBJ:    FrameData {
+; OBJ:      RvaStart: 0x9
+; OBJ:      CodeSize: 0x2B
+; OBJ:      FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebx $T0 4 - ^ = $edi $T0 8 - ^ = $esi $T0 12 - ^ =
+; OBJ:      PrologSize: 0x0
+; OBJ:    }
+; OBJ-NOT: FrameData
+
+; ModuleID = 't.c'
+source_filename = "t.c"
+target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+target triple = "i386-pc-windows-msvc19.11.25508"
+
+; Function Attrs: nounwind
+define x86_fastcallcc i32 @"\01@shrink_wrap_basic@16"(i32 inreg %a, i32 inreg %b, i32 %c, i32 %d) local_unnamed_addr #0 !dbg !8 {
+entry:
+  %c.addr = alloca i32, align 4
+  tail call void @llvm.dbg.value(metadata i32 %d, metadata !13, metadata !DIExpression()), !dbg !19
+  tail call void @llvm.dbg.value(metadata i32 %c, metadata !14, metadata !DIExpression()), !dbg !20
+  store i32 %c, i32* %c.addr, align 4, !tbaa !21
+  tail call void @llvm.dbg.value(metadata i32 %b, metadata !15, metadata !DIExpression()), !dbg !25
+  tail call void @llvm.dbg.value(metadata i32 %a, metadata !16, metadata !DIExpression()), !dbg !26
+  %cmp = icmp slt i32 %a, %b, !dbg !27
+  br i1 %cmp, label %return, label %for.cond.preheader, !dbg !29
+
+for.cond.preheader:                               ; preds = %entry
+  br label %for.cond, !dbg !30
+
+for.cond:                                         ; preds = %for.cond.preheader, %for.cond
+  %i.0 = phi i32 [ %inc, %for.cond ], [ %c, %for.cond.preheader ]
+  call void @llvm.dbg.value(metadata i32 %i.0, metadata !17, metadata !DIExpression()), !dbg !32
+  %cmp1 = icmp slt i32 %i.0, %d, !dbg !30
+  call void @llvm.dbg.value(metadata i32* %c.addr, metadata !14, metadata !DIExpression()), !dbg !20
+  %call = call i32 @doSomething(i32* nonnull %c.addr) #3, !dbg !33
+  %inc = add nsw i32 %i.0, 1, !dbg !34
+  call void @llvm.dbg.value(metadata i32 %inc, metadata !17, metadata !DIExpression()), !dbg !32
+  br i1 %cmp1, label %for.cond, label %return, !dbg !35, !llvm.loop !36
+
+return:                                           ; preds = %for.cond, %entry
+  %retval.0 = phi i32 [ %a, %entry ], [ %call, %for.cond ]
+  ret i32 %retval.0, !dbg !38
+}
+
+declare i32 @doSomething(i32*) local_unnamed_addr #1
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone speculatable }
+attributes #3 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "t.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "32f118fd5dd7e65ff7733c49b2f804ef")
+!2 = !{}
+!3 = !{i32 1, !"NumRegisterParameters", i32 0}
+!4 = !{i32 2, !"CodeView", i32 1}
+!5 = !{i32 2, !"Debug Info Version", i32 3}
+!6 = !{i32 1, !"wchar_size", i32 2}
+!7 = !{!"clang version 6.0.0 "}
+!8 = distinct !DISubprogram(name: "shrink_wrap_basic", linkageName: "\01@shrink_wrap_basic@16", scope: !1, file: !1, line: 2, type: !9, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !12)
+!9 = !DISubroutineType(cc: DW_CC_BORLAND_msfastcall, types: !10)
+!10 = !{!11, !11, !11, !11, !11}
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !{!13, !14, !15, !16, !17}
+!13 = !DILocalVariable(name: "d", arg: 4, scope: !8, file: !1, line: 2, type: !11)
+!14 = !DILocalVariable(name: "c", arg: 3, scope: !8, file: !1, line: 2, type: !11)
+!15 = !DILocalVariable(name: "b", arg: 2, scope: !8, file: !1, line: 2, type: !11)
+!16 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 2, type: !11)
+!17 = !DILocalVariable(name: "i", scope: !18, file: !1, line: 5, type: !11)
+!18 = distinct !DILexicalBlock(scope: !8, file: !1, line: 5, column: 3)
+!19 = !DILocation(line: 2, column: 59, scope: !8)
+!20 = !DILocation(line: 2, column: 52, scope: !8)
+!21 = !{!22, !22, i64 0}
+!22 = !{!"int", !23, i64 0}
+!23 = !{!"omnipotent char", !24, i64 0}
+!24 = !{!"Simple C/C++ TBAA"}
+!25 = !DILocation(line: 2, column: 45, scope: !8)
+!26 = !DILocation(line: 2, column: 38, scope: !8)
+!27 = !DILocation(line: 3, column: 9, scope: !28)
+!28 = distinct !DILexicalBlock(scope: !8, file: !1, line: 3, column: 7)
+!29 = !DILocation(line: 3, column: 7, scope: !8)
+!30 = !DILocation(line: 5, column: 21, scope: !31)
+!31 = distinct !DILexicalBlock(scope: !18, file: !1, line: 5, column: 3)
+!32 = !DILocation(line: 5, column: 12, scope: !18)
+!33 = !DILocation(line: 0, scope: !8)
+!34 = !DILocation(line: 5, column: 26, scope: !31)
+!35 = !DILocation(line: 5, column: 3, scope: !18)
+!36 = distinct !{!36, !35, !37}
+!37 = !DILocation(line: 6, column: 19, scope: !18)
+!38 = !DILocation(line: 8, column: 1, scope: !8)
Index: llvm/test/DebugInfo/COFF/fpo-stack-protect.ll
===================================================================
--- /dev/null
+++ llvm/test/DebugInfo/COFF/fpo-stack-protect.ll
@@ -0,0 +1,114 @@
+; RUN: llc < %s | FileCheck %s
+
+; C source:
+; void escape(int *);
+; int ssp(int a) {
+;   int arr[4] = {a, a, a, a};
+;   escape(&arr[0]);
+;   return a;
+; }
+
+; CHECK: _ssp:                                   # @ssp
+; CHECK:         .cv_fpo_proc    _ssp 4
+; CHECK:         pushl   %esi
+; CHECK:         .cv_fpo_pushreg %esi
+; CHECK:         subl    $20, %esp
+; CHECK:         .cv_fpo_stackalloc      20
+; CHECK:         .cv_fpo_endprologue
+; CHECK:         movl    28(%esp), %esi
+; CHECK:         ___security_cookie
+
+; CHECK:         movl    %esi, {{[0-9]*}}(%esp)
+; CHECK:         movl    %esi, {{[0-9]*}}(%esp)
+; CHECK:         movl    %esi, {{[0-9]*}}(%esp)
+; CHECK:         movl    %esi, {{[0-9]*}}(%esp)
+
+; CHECK:         calll   _escape
+; CHECK:         calll   @__security_check_cookie@4
+
+; CHECK:         movl    %esi, %eax
+; CHECK:         addl    $20, %esp
+; CHECK:         popl    %esi
+; CHECK:         retl
+; CHECK: Ltmp2:
+; CHECK:         .cv_fpo_endproc
+
+; ModuleID = 't.c'
+source_filename = "t.c"
+target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+target triple = "i386-pc-windows-msvc19.11.25508"
+
+; Function Attrs: nounwind sspstrong
+define i32 @ssp(i32 returned %a) local_unnamed_addr #0 !dbg !8 {
+entry:
+  %arr = alloca [4 x i32], align 4
+  tail call void @llvm.dbg.value(metadata i32 %a, metadata !13, metadata !DIExpression()), !dbg !18
+  %0 = bitcast [4 x i32]* %arr to i8*, !dbg !19
+  call void @llvm.lifetime.start.p0i8(i64 16, i8* nonnull %0) #4, !dbg !19
+  tail call void @llvm.dbg.declare(metadata [4 x i32]* %arr, metadata !14, metadata !DIExpression()), !dbg !20
+  %arrayinit.begin = getelementptr inbounds [4 x i32], [4 x i32]* %arr, i32 0, i32 0, !dbg !21
+  store i32 %a, i32* %arrayinit.begin, align 4, !dbg !21, !tbaa !22
+  %arrayinit.element = getelementptr inbounds [4 x i32], [4 x i32]* %arr, i32 0, i32 1, !dbg !21
+  store i32 %a, i32* %arrayinit.element, align 4, !dbg !21, !tbaa !22
+  %arrayinit.element1 = getelementptr inbounds [4 x i32], [4 x i32]* %arr, i32 0, i32 2, !dbg !21
+  store i32 %a, i32* %arrayinit.element1, align 4, !dbg !21, !tbaa !22
+  %arrayinit.element2 = getelementptr inbounds [4 x i32], [4 x i32]* %arr, i32 0, i32 3, !dbg !21
+  store i32 %a, i32* %arrayinit.element2, align 4, !dbg !21, !tbaa !22
+  call void @escape(i32* nonnull %arrayinit.begin) #4, !dbg !26
+  call void @llvm.lifetime.end.p0i8(i64 16, i8* nonnull %0) #4, !dbg !27
+  ret i32 %a, !dbg !28
+}
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #2
+
+declare void @escape(i32*) local_unnamed_addr #3
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #2
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+
+attributes #0 = { nounwind sspstrong "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone speculatable }
+attributes #2 = { argmemonly nounwind }
+attributes #3 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "t.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "df0c1a43acd19a1255d45a3f2802cf9f")
+!2 = !{}
+!3 = !{i32 1, !"NumRegisterParameters", i32 0}
+!4 = !{i32 2, !"CodeView", i32 1}
+!5 = !{i32 2, !"Debug Info Version", i32 3}
+!6 = !{i32 1, !"wchar_size", i32 2}
+!7 = !{!"clang version 6.0.0 "}
+!8 = distinct !DISubprogram(name: "ssp", scope: !1, file: !1, line: 2, type: !9, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !12)
+!9 = !DISubroutineType(types: !10)
+!10 = !{!11, !11}
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !{!13, !14}
+!13 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 2, type: !11)
+!14 = !DILocalVariable(name: "arr", scope: !8, file: !1, line: 3, type: !15)
+!15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 128, elements: !16)
+!16 = !{!17}
+!17 = !DISubrange(count: 4)
+!18 = !DILocation(line: 2, column: 13, scope: !8)
+!19 = !DILocation(line: 3, column: 3, scope: !8)
+!20 = !DILocation(line: 3, column: 7, scope: !8)
+!21 = !DILocation(line: 3, column: 16, scope: !8)
+!22 = !{!23, !23, i64 0}
+!23 = !{!"int", !24, i64 0}
+!24 = !{!"omnipotent char", !25, i64 0}
+!25 = !{!"Simple C/C++ TBAA"}
+!26 = !DILocation(line: 4, column: 3, scope: !8)
+!27 = !DILocation(line: 6, column: 1, scope: !8)
+!28 = !DILocation(line: 5, column: 3, scope: !8)
Index: llvm/test/DebugInfo/COFF/multifunction.ll
===================================================================
--- llvm/test/DebugInfo/COFF/multifunction.ll
+++ llvm/test/DebugInfo/COFF/multifunction.ll
@@ -61,6 +61,7 @@
 ; X86-NEXT: .short [[C1_END:.*]]-[[C1_START:.*]] #
 ; X86:      [[COMPILE_END]]:
 ; X86-NEXT: .p2align 2
+; X86-NEXT: .cv_fpo_data _x
 ; Symbol subsection for x
 ; X86-NEXT: .long   241
 ; X86-NEXT: .long [[F1_END:.*]]-[[F1_START:.*]] #
@@ -87,6 +88,7 @@
 ; Line table subsection for x
 ; X86: .cv_linetable 0, _x, [[END_OF_X]]
 ; Symbol subsection for y
+; X86-NEXT: .cv_fpo_data _y
 ; X86-NEXT: .long   241
 ; X86-NEXT: .long [[COMPILE_END:.*]]-[[COMPILE_START:.*]] #
 ; X86-NEXT: [[COMPILE_START]]:
@@ -112,6 +114,7 @@
 ; Line table subsection for y
 ; X86: .cv_linetable 1, _y, [[END_OF_Y]]
 ; Symbol subsection for f
+; X86-NEXT: .cv_fpo_data _f
 ; X86-NEXT: .long   241
 ; X86-NEXT: .long [[COMPILE_END:.*]]-[[COMPILE_START:.*]] #
 ; X86-NEXT: [[COMPILE_START]]:
@@ -145,6 +148,13 @@
 ; OBJ32:      ]
 ; OBJ32:      Subsection [
 ; OBJ32-NEXT:   SubSectionType: Symbols (0xF1)
+; OBJ32: 	Compile3Sym
+; OBJ32:      ]
+; OBJ32:      Subsection [
+; OBJ32-NEXT:   SubSectionType: FrameData (0xF5)
+; OBJ32:      ]
+; OBJ32:      Subsection [
+; OBJ32-NEXT:   SubSectionType: Symbols (0xF1)
 ; OBJ32:        {{.*}}Proc{{.*}}Sym {
 ; OBJ32:          Kind: S_LPROC32_ID (0x1146)
 ; OBJ32:          CodeSize: 0x6
@@ -158,6 +168,9 @@
 ; OBJ32-NEXT:   SubSectionType: Lines (0xF2)
 ; OBJ32:      ]
 ; OBJ32:      Subsection [
+; OBJ32-NEXT:   SubSectionType: FrameData (0xF5)
+; OBJ32:      ]
+; OBJ32:      Subsection [
 ; OBJ32-NEXT:   SubSectionType: Symbols (0xF1)
 ; OBJ32:        {{.*}}Proc{{.*}}Sym {
 ; OBJ32:          Kind: S_GPROC32_ID (0x1147)
@@ -172,6 +185,9 @@
 ; OBJ32-NEXT:   SubSectionType: Lines (0xF2)
 ; OBJ32:      ]
 ; OBJ32:      Subsection [
+; OBJ32-NEXT:   SubSectionType: FrameData (0xF5)
+; OBJ32:      ]
+; OBJ32:      Subsection [
 ; OBJ32-NEXT:   SubSectionType: Symbols (0xF1)
 ; OBJ32:        {{.*}}Proc{{.*}}Sym {
 ; OBJ32:          Kind: S_GPROC32_ID (0x1147)
Index: llvm/test/DebugInfo/COFF/simple.ll
===================================================================
--- llvm/test/DebugInfo/COFF/simple.ll
+++ llvm/test/DebugInfo/COFF/simple.ll
@@ -36,6 +36,7 @@
 ; X86:      [[C1_END]]:
 ; X86-NEXT: [[COMPILE_END]]:
 ; X86-NEXT: .p2align	2
+; X86-NEXT:	.cv_fpo_data _f
 ; X86-NEXT:	.long	241  # Symbol subsection for f
 ; X86-NEXT:	.long	[[F1_END:.*]]-[[F1_START:.*]] # Subsection size
 ; X86-NEXT: [[F1_START]]:
@@ -70,13 +71,21 @@
 ; OBJ32:      Characteristics [ (0x42300040)
 ; OBJ32:      ]
 ; OBJ32:      Relocations [
-; OBJ32-NEXT:   0x64 IMAGE_REL_I386_SECREL _f
-; OBJ32-NEXT:   0x68 IMAGE_REL_I386_SECTION _f
-; OBJ32-NEXT:   0x7C IMAGE_REL_I386_SECREL _f
-; OBJ32-NEXT:   0x80 IMAGE_REL_I386_SECTION _f
+; OBJ32-NEXT:   0x44 IMAGE_REL_I386_DIR32NB _f
+; OBJ32-NEXT:   0x90 IMAGE_REL_I386_SECREL _f
+; OBJ32-NEXT:   0x94 IMAGE_REL_I386_SECTION _f
+; OBJ32-NEXT:   0xA8 IMAGE_REL_I386_SECREL _f
+; OBJ32-NEXT:   0xAC IMAGE_REL_I386_SECTION _f
 ; OBJ32-NEXT: ]
 ; OBJ32:      Subsection [
 ; OBJ32-NEXT:   SubSectionType: Symbols (0xF1)
+; OBJ32: 	Compile3Sym
+; OBJ32:      ]
+; OBJ32:      Subsection [
+; OBJ32-NEXT:   SubSectionType: FrameData (0xF5)
+; OBJ32:      ]
+; OBJ32:      Subsection [
+; OBJ32-NEXT:   SubSectionType: Symbols (0xF1)
 ; OBJ32:        {{.*}}Proc{{.*}}Sym {
 ; OBJ32:          CodeSize: 0x6
 ; OBJ32:          DisplayName: f
Index: llvm/test/MC/COFF/cv-fpo-csrs.s
===================================================================
--- /dev/null
+++ llvm/test/MC/COFF/cv-fpo-csrs.s
@@ -0,0 +1,141 @@
+# RUN: llvm-mc -filetype=asm < %s -triple i686-windows-msvc | FileCheck %s --check-prefix=ASM
+# RUN: llvm-mc -filetype=obj < %s -triple i686-windows-msvc | llvm-readobj -codeview | FileCheck %s --check-prefix=OBJ
+
+.globl _foo
+_foo:
+	.cv_fpo_proc _foo 4
+	pushl	%ebp
+	.cv_fpo_pushreg ebp # Test without %
+	pushl	%ebx
+	.cv_fpo_pushreg %ebx
+	pushl	%edi
+	.cv_fpo_pushreg %edi
+	pushl	%esi
+	.cv_fpo_pushreg esi
+	subl $20, %esp
+	.cv_fpo_stackalloc 20
+	.cv_fpo_endprologue
+
+	# ASM: .cv_fpo_proc _foo 4
+	# ASM: pushl	%ebp
+	# ASM: .cv_fpo_pushreg %ebp
+	# ASM: pushl	%ebx
+	# ASM: .cv_fpo_pushreg %ebx
+	# ASM: pushl	%edi
+	# ASM: .cv_fpo_pushreg %edi
+	# ASM: pushl	%esi
+	# ASM: .cv_fpo_pushreg %esi
+	# ASM: subl $20, %esp
+	# ASM: .cv_fpo_stackalloc 20
+	# ASM: .cv_fpo_endprologue
+
+	# Clobbers
+	xorl %ebp, %ebp
+	xorl %ebx, %ebx
+	xorl %edi, %edi
+	xorl %esi, %esi
+	# Use that stack memory
+	leal 4(%esp), %eax
+	movl %eax, (%esp)
+	calll _bar
+
+	# ASM: calll _bar
+
+	# Epilogue
+	# FIXME: Get FPO data for this once we get it for DWARF.
+	addl $20, %esp
+	popl %esi
+	popl %edi
+	popl %ebx
+	popl %ebp
+	retl
+	.cv_fpo_endproc
+
+	# ASM: .cv_fpo_endproc
+
+	.section	.debug$S,"dr"
+	.p2align	2
+	.long	4                       # Debug section magic
+	.cv_fpo_data _foo
+	.cv_stringtable
+
+	# ASM: .cv_fpo_data
+
+# OBJ:       Subsection [
+# OBJ-NEXT:    SubSectionType: FrameData (0xF5)
+# OBJ-NEXT:    SubSectionSize: 0xC4
+# OBJ-NEXT:    LinkageName: _foo
+# OBJ-NEXT:    FrameData {
+# OBJ-NEXT:      RvaStart: 0x0
+# OBJ-NEXT:      CodeSize: 0x23
+# OBJ-NEXT:      LocalSize: 0x0
+# OBJ-NEXT:      ParamsSize: 0x4
+# OBJ-NEXT:      MaxStackSize: 0x0
+# OBJ-NEXT:      FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+# OBJ-NEXT:      PrologSize: 0x7
+# OBJ-NEXT:      SavedRegsSize: 0x0
+# OBJ-NEXT:      Flags [ (0x4)
+# OBJ-NEXT:        IsFunctionStart (0x4)
+# OBJ-NEXT:      ]
+# OBJ-NEXT:    }
+# OBJ-NEXT:    FrameData {
+# OBJ-NEXT:      RvaStart: 0x1
+# OBJ-NEXT:      CodeSize: 0x22
+# OBJ-NEXT:      LocalSize: 0x0
+# OBJ-NEXT:      ParamsSize: 0x4
+# OBJ-NEXT:      MaxStackSize: 0x0
+# OBJ-NEXT:      FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
+# OBJ-NEXT:      PrologSize: 0x6
+# OBJ-NEXT:      SavedRegsSize: 0x4
+# OBJ-NEXT:      Flags [ (0x0)
+# OBJ-NEXT:      ]
+# OBJ-NEXT:    }
+# OBJ-NEXT:    FrameData {
+# OBJ-NEXT:      RvaStart: 0x2
+# OBJ-NEXT:      CodeSize: 0x21
+# OBJ-NEXT:      LocalSize: 0x0
+# OBJ-NEXT:      ParamsSize: 0x4
+# OBJ-NEXT:      MaxStackSize: 0x0
+# OBJ-NEXT:      FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ =
+# OBJ-NEXT:      PrologSize: 0x5
+# OBJ-NEXT:      SavedRegsSize: 0x8
+# OBJ-NEXT:      Flags [ (0x0)
+# OBJ-NEXT:      ]
+# OBJ-NEXT:    }
+# OBJ-NEXT:    FrameData {
+# OBJ-NEXT:      RvaStart: 0x3
+# OBJ-NEXT:      CodeSize: 0x20
+# OBJ-NEXT:      LocalSize: 0x0
+# OBJ-NEXT:      ParamsSize: 0x4
+# OBJ-NEXT:      MaxStackSize: 0x0
+# OBJ-NEXT:      FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ =
+# OBJ-NEXT:      PrologSize: 0x4
+# OBJ-NEXT:      SavedRegsSize: 0xC
+# OBJ-NEXT:      Flags [ (0x0)
+# OBJ-NEXT:      ]
+# OBJ-NEXT:    }
+# OBJ-NEXT:    FrameData {
+# OBJ-NEXT:      RvaStart: 0x4
+# OBJ-NEXT:      CodeSize: 0x1F
+# OBJ-NEXT:      LocalSize: 0x0
+# OBJ-NEXT:      ParamsSize: 0x4
+# OBJ-NEXT:      MaxStackSize: 0x0
+# OBJ-NEXT:      FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ = $esi $T0 16 - ^ =
+# OBJ-NEXT:      PrologSize: 0x3
+# OBJ-NEXT:      SavedRegsSize: 0x10
+# OBJ-NEXT:      Flags [ (0x0)
+# OBJ-NEXT:      ]
+# OBJ-NEXT:    }
+# OBJ-NEXT:    FrameData {
+# OBJ-NEXT:      RvaStart: 0x7
+# OBJ-NEXT:      CodeSize: 0x1C
+# OBJ-NEXT:      LocalSize: 0x14
+# OBJ-NEXT:      ParamsSize: 0x4
+# OBJ-NEXT:      MaxStackSize: 0x0
+# OBJ-NEXT:      FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ = $esi $T0 16 - ^ =
+# OBJ-NEXT:      PrologSize: 0x0
+# OBJ-NEXT:      SavedRegsSize: 0x10
+# OBJ-NEXT:      Flags [ (0x0)
+# OBJ-NEXT:      ]
+# OBJ-NEXT:    }
+# OBJ-NOT: FrameData
Index: llvm/test/MC/COFF/cv-fpo-errors.s
===================================================================
--- /dev/null
+++ llvm/test/MC/COFF/cv-fpo-errors.s
@@ -0,0 +1,47 @@
+# RUN: not llvm-mc < %s -triple i686-windows-msvc -o /dev/null 2>&1 | FileCheck %s --implicit-check-not=error:
+
+.globl _foo
+_foo:
+	.cv_fpo_proc
+	# CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected symbol name
+	.cv_fpo_proc 1
+	# CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected symbol name
+	.cv_fpo_proc _foo extra
+	# CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected parameter byte count
+	.cv_fpo_proc _foo 4 extra
+	# CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: unexpected tokens in '.cv_fpo_proc' directive
+	.cv_fpo_proc _foo 4
+
+	pushl	%ebp
+	.cv_fpo_pushreg 1
+	# CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid register name in '.cv_fpo_pushreg' directive
+	.cv_fpo_pushreg ebp
+
+	subl $20, %esp
+	.cv_fpo_stackalloc asdf
+	# CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected offset in '.cv_fpo_stackalloc' directive
+	.cv_fpo_stackalloc 20 asdf
+	# CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: unexpected tokens in '.cv_fpo_stackalloc' directive
+	.cv_fpo_stackalloc 20
+	.cv_fpo_endprologue asdf
+	# CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: unexpected tokens in '.cv_fpo_endprologue' directive
+	.cv_fpo_endprologue
+
+	addl $20, %esp
+	popl %ebp
+	retl
+	.cv_fpo_endproc asdf
+	# CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: unexpected tokens in '.cv_fpo_endproc' directive
+	.cv_fpo_endproc
+
+	.section	.debug$S,"dr"
+	.p2align	2
+	.long	4                       # Debug section magic
+	.cv_fpo_data
+	# CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected symbol name
+	.cv_fpo_data 1
+	# CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected symbol name
+	.cv_fpo_data _foo asdf
+	# CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: unexpected tokens in '.cv_fpo_data' directive
+	.cv_fpo_data _foo
+	.long 0
Index: llvm/test/MC/COFF/cv-fpo-setframe.s
===================================================================
--- /dev/null
+++ llvm/test/MC/COFF/cv-fpo-setframe.s
@@ -0,0 +1,144 @@
+# RUN: llvm-mc -filetype=asm < %s -triple i686-windows-msvc | FileCheck %s --check-prefix=ASM
+# RUN: llvm-mc -filetype=obj < %s -triple i686-windows-msvc | llvm-readobj -codeview | FileCheck %s --check-prefix=OBJ
+
+.globl _foo
+_foo:
+	.cv_fpo_proc _foo 4
+	pushl	%ebp
+	.cv_fpo_pushreg %ebp
+	movl	%ebp, %esp
+	.cv_fpo_setframe %ebp
+	pushl	%ebx
+	.cv_fpo_pushreg %ebx
+	pushl	%edi
+	.cv_fpo_pushreg %edi
+	pushl	%esi
+	.cv_fpo_pushreg esi
+	subl $20, %esp
+	.cv_fpo_stackalloc 20
+	.cv_fpo_endprologue
+
+	# ASM: .cv_fpo_proc _foo 4
+	# ASM: pushl	%ebp
+	# ASM: .cv_fpo_pushreg %ebp
+	# ASM: movl	%ebp, %esp
+	# ASM: .cv_fpo_setframe %ebp
+	# ASM: pushl	%ebx
+	# ASM: .cv_fpo_pushreg %ebx
+	# ASM: pushl	%edi
+	# ASM: .cv_fpo_pushreg %edi
+	# ASM: pushl	%esi
+	# ASM: .cv_fpo_pushreg %esi
+	# ASM: subl $20, %esp
+	# ASM: .cv_fpo_stackalloc 20
+	# ASM: .cv_fpo_endprologue
+
+	# Clobbers
+	xorl %ebx, %ebx
+	xorl %edi, %edi
+	xorl %esi, %esi
+	# Use that stack memory
+	leal 4(%esp), %eax
+	movl %eax, (%esp)
+	calll _bar
+
+	# ASM: calll _bar
+
+	# Epilogue
+	# FIXME: Get FPO data for this once we get it for DWARF.
+	addl $20, %esp
+	popl %esi
+	popl %edi
+	popl %ebx
+	popl %ebp
+	retl
+	.cv_fpo_endproc
+
+	# ASM: .cv_fpo_endproc
+
+	.section	.debug$S,"dr"
+	.p2align	2
+	.long	4                       # Debug section magic
+	.cv_fpo_data _foo
+	.cv_stringtable
+
+	# ASM: .cv_fpo_data
+
+# OBJ:       Subsection [
+# OBJ-NEXT:    SubSectionType: FrameData (0xF5)
+# OBJ-NEXT:    SubSectionSize:
+# OBJ-NEXT:    LinkageName: _foo
+# OBJ-NEXT:    FrameData {
+# OBJ-NEXT:      RvaStart: 0x0
+# OBJ-NEXT:      CodeSize: 0x23
+# OBJ-NEXT:      LocalSize: 0x0
+# OBJ-NEXT:      ParamsSize: 0x4
+# OBJ-NEXT:      MaxStackSize: 0x0
+# OBJ-NEXT:      FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+# OBJ-NEXT:      PrologSize: 0x9
+# OBJ-NEXT:      SavedRegsSize: 0x0
+# OBJ-NEXT:      Flags [ (0x4)
+# OBJ-NEXT:        IsFunctionStart (0x4)
+# OBJ-NEXT:      ]
+# OBJ-NEXT:    }
+# OBJ-NEXT:    FrameData {
+# OBJ-NEXT:      RvaStart: 0x1
+# OBJ-NEXT:      CodeSize: 0x22
+# OBJ-NEXT:      LocalSize: 0x0
+# OBJ-NEXT:      ParamsSize: 0x4
+# OBJ-NEXT:      MaxStackSize: 0x0
+# OBJ-NEXT:      FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
+# OBJ-NEXT:      PrologSize: 0x8
+# OBJ-NEXT:      SavedRegsSize: 0x4
+# OBJ-NEXT:      Flags [ (0x0)
+# OBJ-NEXT:      ]
+# OBJ-NEXT:    }
+# OBJ-NEXT:    FrameData {
+# OBJ-NEXT:      RvaStart: 0x3
+# OBJ-NEXT:      CodeSize: 0x20
+# OBJ-NEXT:      LocalSize: 0x0
+# OBJ-NEXT:      ParamsSize: 0x4
+# OBJ-NEXT:      MaxStackSize: 0x0
+# OBJ-NEXT:      FrameFunc: $T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
+# OBJ-NEXT:      PrologSize: 0x6
+# OBJ-NEXT:      SavedRegsSize: 0x4
+# OBJ-NEXT:      Flags [ (0x0)
+# OBJ-NEXT:      ]
+# OBJ-NEXT:    }
+# OBJ-NEXT:    FrameData {
+# OBJ-NEXT:      RvaStart: 0x4
+# OBJ-NEXT:      CodeSize: 0x1F
+# OBJ-NEXT:      LocalSize: 0x0
+# OBJ-NEXT:      ParamsSize: 0x4
+# OBJ-NEXT:      MaxStackSize: 0x0
+# OBJ-NEXT:      FrameFunc: $T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ =
+# OBJ-NEXT:      PrologSize: 0x5
+# OBJ-NEXT:      SavedRegsSize: 0x8
+# OBJ-NEXT:      Flags [ (0x0)
+# OBJ-NEXT:      ]
+# OBJ-NEXT:    }
+# OBJ-NEXT:    FrameData {
+# OBJ-NEXT:      RvaStart: 0x5
+# OBJ-NEXT:      CodeSize: 0x1E
+# OBJ-NEXT:      LocalSize: 0x0
+# OBJ-NEXT:      ParamsSize: 0x4
+# OBJ-NEXT:      MaxStackSize: 0x0
+# OBJ-NEXT:      FrameFunc: $T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ =
+# OBJ-NEXT:      PrologSize: 0x4
+# OBJ-NEXT:      SavedRegsSize: 0xC
+# OBJ-NEXT:      Flags [ (0x0)
+# OBJ-NEXT:      ]
+# OBJ-NEXT:    }
+# OBJ-NEXT:    FrameData {
+# OBJ-NEXT:      RvaStart: 0x6
+# OBJ-NEXT:      CodeSize: 0x1D
+# OBJ-NEXT:      LocalSize: 0x0
+# OBJ-NEXT:      ParamsSize: 0x4
+# OBJ-NEXT:      MaxStackSize: 0x0
+# OBJ-NEXT:      FrameFunc: $T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ = $esi $T0 16 - ^ =
+# OBJ-NEXT:      PrologSize: 0x3
+# OBJ-NEXT:      SavedRegsSize: 0x10
+# OBJ-NEXT:      Flags [ (0x0)
+# OBJ-NEXT:      ]
+# OBJ-NEXT:    }
+# OBJ-NOT: FrameData