[llvm] r315513 - [codeview] Implement FPO data assembler directives

Reid Kleckner via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 11 14:24:33 PDT 2017


Author: rnk
Date: Wed Oct 11 14:24:33 2017
New Revision: 315513

URL: http://llvm.org/viewvc/llvm-project?rev=315513&view=rev
Log:
[codeview] Implement FPO data assembler directives

Summary:
This adds a set of new directives that describe 32-bit x86 prologues.
The directives are limited and do not expose the full complexity of
codeview FPO data. They are merely a convenience for the compiler to
generate more readable assembly so we don't need to generate tons of
labels in CodeGen. If our prologue emission changes in the future, we
can change the set of available directives to suit our needs. These are
modelled after the .seh_ directives, which use a different format that
interacts with exception handling.

The directives are:
  .cv_fpo_proc _foo
  .cv_fpo_pushreg ebp/ebx/etc
  .cv_fpo_setframe ebp/esi/etc
  .cv_fpo_stackalloc 200
  .cv_fpo_endprologue
  .cv_fpo_endproc
  .cv_fpo_data _foo

I tried to follow the implementation of ARM EHABI CFI directives by
sinking most directives out of MCStreamer and into X86TargetStreamer.
This helps avoid polluting non-X86 code with WinCOFF specific logic.

I used cdb to confirm that this can show locals in parent CSRs in a few
cases, most importantly the one where we use ESI as a frame pointer,
i.e. the one in http://crbug.com/756153#c28

Once we have cdb integration in debuginfo-tests, we can add integration
tests there.

Reviewers: majnemer, hans

Subscribers: aemerson, mgorny, kristof.beyls, llvm-commits, hiraditya

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

Added:
    llvm/trunk/lib/Target/X86/MCTargetDesc/X86TargetStreamer.h
    llvm/trunk/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp
    llvm/trunk/test/DebugInfo/COFF/fpo-argsize.ll
    llvm/trunk/test/DebugInfo/COFF/fpo-csrs.ll
    llvm/trunk/test/DebugInfo/COFF/fpo-realign-alloca.ll
    llvm/trunk/test/DebugInfo/COFF/fpo-shrink-wrap.ll
    llvm/trunk/test/DebugInfo/COFF/fpo-stack-protect.ll
    llvm/trunk/test/MC/COFF/cv-fpo-csrs.s
    llvm/trunk/test/MC/COFF/cv-fpo-errors.s
    llvm/trunk/test/MC/COFF/cv-fpo-setframe.s
Modified:
    llvm/trunk/include/llvm/MC/MCCodeView.h
    llvm/trunk/include/llvm/MC/MCStreamer.h
    llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
    llvm/trunk/lib/MC/MCAsmStreamer.cpp
    llvm/trunk/lib/MC/MCParser/AsmParser.cpp
    llvm/trunk/lib/Target/X86/AsmParser/X86AsmParser.cpp
    llvm/trunk/lib/Target/X86/MCTargetDesc/CMakeLists.txt
    llvm/trunk/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
    llvm/trunk/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h
    llvm/trunk/lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp
    llvm/trunk/lib/Target/X86/X86AsmPrinter.cpp
    llvm/trunk/lib/Target/X86/X86AsmPrinter.h
    llvm/trunk/lib/Target/X86/X86FrameLowering.cpp
    llvm/trunk/lib/Target/X86/X86MCInstLower.cpp
    llvm/trunk/lib/Target/X86/X86Subtarget.h
    llvm/trunk/test/DebugInfo/COFF/asan-module-ctor.ll
    llvm/trunk/test/DebugInfo/COFF/multifunction.ll
    llvm/trunk/test/DebugInfo/COFF/simple.ll

Modified: llvm/trunk/include/llvm/MC/MCCodeView.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCCodeView.h?rev=315513&r1=315512&r2=315513&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCCodeView.h (original)
+++ llvm/trunk/include/llvm/MC/MCCodeView.h Wed Oct 11 14:24:33 2017
@@ -276,6 +276,10 @@ public:
   /// 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 @@ private:
 
   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);
 

Modified: llvm/trunk/include/llvm/MC/MCStreamer.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCStreamer.h?rev=315513&r1=315512&r2=315513&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCStreamer.h (original)
+++ llvm/trunk/include/llvm/MC/MCStreamer.h Wed Oct 11 14:24:33 2017
@@ -790,6 +790,9 @@ public:
   /// 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.

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp?rev=315513&r1=315512&r2=315513&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp Wed Oct 11 14:24:33 2017
@@ -808,6 +808,10 @@ void CodeViewDebug::emitDebugInfoForFunc
   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);

Modified: llvm/trunk/lib/MC/MCAsmStreamer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCAsmStreamer.cpp?rev=315513&r1=315512&r2=315513&view=diff
==============================================================================
--- llvm/trunk/lib/MC/MCAsmStreamer.cpp (original)
+++ llvm/trunk/lib/MC/MCAsmStreamer.cpp Wed Oct 11 14:24:33 2017
@@ -248,6 +248,7 @@ public:
   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 @@ void MCAsmStreamer::EmitCVFileChecksumOf
   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";

Modified: llvm/trunk/lib/MC/MCParser/AsmParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCParser/AsmParser.cpp?rev=315513&r1=315512&r2=315513&view=diff
==============================================================================
--- llvm/trunk/lib/MC/MCParser/AsmParser.cpp (original)
+++ llvm/trunk/lib/MC/MCParser/AsmParser.cpp Wed Oct 11 14:24:33 2017
@@ -503,6 +503,7 @@ private:
     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 @@ private:
   bool parseDirectiveCVStringTable();
   bool parseDirectiveCVFileChecksums();
   bool parseDirectiveCVFileChecksumOffset();
+  bool parseDirectiveCVFPOData();
 
   // .cfi directives
   bool parseDirectiveCFIRegister(SMLoc DirectiveLoc);
@@ -2039,6 +2041,8 @@ bool AsmParser::parseStatement(ParseStat
       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 @@ bool AsmParser::parseDirectiveCVFileChec
   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 @@ void AsmParser::initializeDirectiveKindM
   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;

Modified: llvm/trunk/lib/Target/X86/AsmParser/X86AsmParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/AsmParser/X86AsmParser.cpp?rev=315513&r1=315512&r2=315513&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/AsmParser/X86AsmParser.cpp (original)
+++ llvm/trunk/lib/Target/X86/AsmParser/X86AsmParser.cpp Wed Oct 11 14:24:33 2017
@@ -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 @@ private:
     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 @@ private:
   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 @@ bool X86AsmParser::ParseDirective(AsmTok
     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 @@ bool X86AsmParser::ParseDirectiveCode(St
   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());

Modified: llvm/trunk/lib/Target/X86/MCTargetDesc/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/MCTargetDesc/CMakeLists.txt?rev=315513&r1=315512&r2=315513&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/MCTargetDesc/CMakeLists.txt (original)
+++ llvm/trunk/lib/Target/X86/MCTargetDesc/CMakeLists.txt Wed Oct 11 14:24:33 2017
@@ -5,6 +5,7 @@ add_llvm_library(LLVMX86Desc
   X86MCCodeEmitter.cpp
   X86MachObjectWriter.cpp
   X86ELFObjectWriter.cpp
-  X86WinCOFFStreamer.cpp
   X86WinCOFFObjectWriter.cpp
+  X86WinCOFFStreamer.cpp
+  X86WinCOFFTargetStreamer.cpp
   )

Modified: llvm/trunk/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp?rev=315513&r1=315512&r2=315513&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp (original)
+++ llvm/trunk/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp Wed Oct 11 14:24:33 2017
@@ -319,7 +319,13 @@ extern "C" void LLVMInitializeX86TargetM
     // 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.

Modified: llvm/trunk/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h?rev=315513&r1=315512&r2=315513&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h (original)
+++ llvm/trunk/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h Wed Oct 11 14:24:33 2017
@@ -77,6 +77,16 @@ MCAsmBackend *createX86_64AsmBackend(con
                                      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.
 ///

Added: llvm/trunk/lib/Target/X86/MCTargetDesc/X86TargetStreamer.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/MCTargetDesc/X86TargetStreamer.h?rev=315513&view=auto
==============================================================================
--- llvm/trunk/lib/Target/X86/MCTargetDesc/X86TargetStreamer.h (added)
+++ llvm/trunk/lib/Target/X86/MCTargetDesc/X86TargetStreamer.h Wed Oct 11 14:24:33 2017
@@ -0,0 +1,34 @@
+//===- 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

Modified: llvm/trunk/lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp?rev=315513&r1=315512&r2=315513&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp (original)
+++ llvm/trunk/lib/Target/X86/MCTargetDesc/X86WinCOFFStreamer.cpp Wed Oct 11 14:24:33 2017
@@ -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 @@ public:
 
   void EmitWinEHHandlerData(SMLoc Loc) override;
   void EmitWindowsUnwindTables() override;
+  void EmitCVFPOData(const MCSymbol *ProcSym, SMLoc Loc) override;
   void FinishImpl() override;
 };
 
@@ -41,6 +43,12 @@ void X86WinCOFFStreamer::EmitWindowsUnwi
   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();

Added: llvm/trunk/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp?rev=315513&view=auto
==============================================================================
--- llvm/trunk/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp (added)
+++ llvm/trunk/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp Wed Oct 11 14:24:33 2017
@@ -0,0 +1,415 @@
+//===-- 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 {
+  RegSaveOffset(unsigned Reg, unsigned Offset) : Reg(Reg), Offset(Offset) {}
+
+  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;
+
+  // MSVC has only ever been observed to emit a MaxStackSize of zero.
+  unsigned MaxStackSize = 0;
+
+  // 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(MaxStackSize, 4);
+  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);
+}

Modified: llvm/trunk/lib/Target/X86/X86AsmPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86AsmPrinter.cpp?rev=315513&r1=315512&r2=315513&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86AsmPrinter.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86AsmPrinter.cpp Wed Oct 11 14:24:33 2017
@@ -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 @@ bool X86AsmPrinter::runOnMachineFunction
 
   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 @@ bool X86AsmPrinter::runOnMachineFunction
   // 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.

Modified: llvm/trunk/lib/Target/X86/X86AsmPrinter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86AsmPrinter.h?rev=315513&r1=315512&r2=315513&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86AsmPrinter.h (original)
+++ llvm/trunk/lib/Target/X86/X86AsmPrinter.h Wed Oct 11 14:24:33 2017
@@ -30,6 +30,7 @@ class LLVM_LIBRARY_VISIBILITY X86AsmPrin
   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 @@ class LLVM_LIBRARY_VISIBILITY X86AsmPrin
   // 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 @@ public:
   }
 
   bool runOnMachineFunction(MachineFunction &F) override;
+  void EmitFunctionBodyStart() override;
+  void EmitFunctionBodyEnd() override;
 };
 
 } // end namespace llvm

Modified: llvm/trunk/lib/Target/X86/X86FrameLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86FrameLowering.cpp?rev=315513&r1=315512&r2=315513&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86FrameLowering.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86FrameLowering.cpp Wed Oct 11 14:24:33 2017
@@ -924,6 +924,7 @@ void X86FrameLowering::BuildStackAlignAN
 
   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 @@ void X86FrameLowering::emitPrologue(Mach
   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 @@ void X86FrameLowering::emitPrologue(Mach
           ? 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 @@ void X86FrameLowering::emitPrologue(Mach
         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 @@ void X86FrameLowering::emitPrologue(Mach
 
     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 @@ void X86FrameLowering::emitPrologue(Mach
 
     // 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 @@ void X86FrameLowering::emitPrologue(Mach
           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 @@ void X86FrameLowering::emitEpilogue(Mach
       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 @@ void X86FrameLowering::emitEpilogue(Mach
   // 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())) {

Modified: llvm/trunk/lib/Target/X86/X86MCInstLower.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86MCInstLower.cpp?rev=315513&r1=315512&r2=315513&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86MCInstLower.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86MCInstLower.cpp Wed Oct 11 14:24:33 2017
@@ -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 @@ static void printConstant(const Constant
   }
 }
 
+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 @@ void X86AsmPrinter::EmitInstruction(cons
     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: {

Modified: llvm/trunk/lib/Target/X86/X86Subtarget.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86Subtarget.h?rev=315513&r1=315512&r2=315513&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86Subtarget.h (original)
+++ llvm/trunk/lib/Target/X86/X86Subtarget.h Wed Oct 11 14:24:33 2017
@@ -592,13 +592,9 @@ public:
 
   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; }

Modified: llvm/trunk/test/DebugInfo/COFF/asan-module-ctor.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/COFF/asan-module-ctor.ll?rev=315513&r1=315512&r2=315513&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/COFF/asan-module-ctor.ll (original)
+++ llvm/trunk/test/DebugInfo/COFF/asan-module-ctor.ll Wed Oct 11 14:24:33 2017
@@ -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
 

Added: llvm/trunk/test/DebugInfo/COFF/fpo-argsize.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/COFF/fpo-argsize.ll?rev=315513&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/COFF/fpo-argsize.ll (added)
+++ llvm/trunk/test/DebugInfo/COFF/fpo-argsize.ll Wed Oct 11 14:24:33 2017
@@ -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 at 4 0
+; CHECK: .cv_fpo_proc    @fastcall2 at 8 0
+; CHECK: .cv_fpo_proc    @fastcall3 at 12 4
+
+; CHECK: .cv_fpo_proc    _stdcall1 at 4 4
+; CHECK: .cv_fpo_proc    _stdcall2 at 8 8
+; CHECK: .cv_fpo_proc    _stdcall3 at 12 12
+
+; 'this' is in ecx and doesn't count.
+; CHECK: .cv_fpo_proc    "?thiscall1 at Foo@@QAEXH at Z" 4
+; CHECK: .cv_fpo_proc    "?thiscall2 at Foo@@QAEXHH at Z" 8
+; CHECK: .cv_fpo_proc    "?thiscall3 at Foo@@QAEXHHH at 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 }
+
+ at 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 at 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 at 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 at 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 at 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 at 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 at 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 at Foo@@QAEXH at 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 at Foo@@QAEXHH at 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 at Foo@@QAEXHHH at 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 at 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 at 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 at 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 at 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 at 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 at 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 at Foo@@QAEXH at 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 at Foo@@QAEXH at 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 at Foo@@QAEXHH at 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 at Foo@@QAEXHHH at 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 at Foo@@QAEXHH at 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 at Foo@@QAEXHHH at 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)

Added: llvm/trunk/test/DebugInfo/COFF/fpo-csrs.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/COFF/fpo-csrs.ll?rev=315513&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/COFF/fpo-csrs.ll (added)
+++ llvm/trunk/test/DebugInfo/COFF/fpo-csrs.ll Wed Oct 11 14:24:33 2017
@@ -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)

Added: llvm/trunk/test/DebugInfo/COFF/fpo-realign-alloca.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/COFF/fpo-realign-alloca.ll?rev=315513&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/COFF/fpo-realign-alloca.ll (added)
+++ llvm/trunk/test/DebugInfo/COFF/fpo-realign-alloca.ll Wed Oct 11 14:24:33 2017
@@ -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)

Added: llvm/trunk/test/DebugInfo/COFF/fpo-shrink-wrap.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/COFF/fpo-shrink-wrap.ll?rev=315513&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/COFF/fpo-shrink-wrap.ll (added)
+++ llvm/trunk/test/DebugInfo/COFF/fpo-shrink-wrap.ll Wed Oct 11 14:24:33 2017
@@ -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 at 16:                  # @"\01 at shrink_wrap_basic@16"
+; ASM:         .cv_fpo_proc    @shrink_wrap_basic at 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 at 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 at 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)

Added: llvm/trunk/test/DebugInfo/COFF/fpo-stack-protect.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/COFF/fpo-stack-protect.ll?rev=315513&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/COFF/fpo-stack-protect.ll (added)
+++ llvm/trunk/test/DebugInfo/COFF/fpo-stack-protect.ll Wed Oct 11 14:24:33 2017
@@ -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:         ___security_cookie
+
+; CHECK:         movl    28(%esp), %esi
+; 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 at 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)

Modified: llvm/trunk/test/DebugInfo/COFF/multifunction.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/COFF/multifunction.ll?rev=315513&r1=315512&r2=315513&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/COFF/multifunction.ll (original)
+++ llvm/trunk/test/DebugInfo/COFF/multifunction.ll Wed Oct 11 14:24:33 2017
@@ -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)

Modified: llvm/trunk/test/DebugInfo/COFF/simple.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/COFF/simple.ll?rev=315513&r1=315512&r2=315513&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/COFF/simple.ll (original)
+++ llvm/trunk/test/DebugInfo/COFF/simple.ll Wed Oct 11 14:24:33 2017
@@ -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

Added: llvm/trunk/test/MC/COFF/cv-fpo-csrs.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/COFF/cv-fpo-csrs.s?rev=315513&view=auto
==============================================================================
--- llvm/trunk/test/MC/COFF/cv-fpo-csrs.s (added)
+++ llvm/trunk/test/MC/COFF/cv-fpo-csrs.s Wed Oct 11 14:24:33 2017
@@ -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

Added: llvm/trunk/test/MC/COFF/cv-fpo-errors.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/COFF/cv-fpo-errors.s?rev=315513&view=auto
==============================================================================
--- llvm/trunk/test/MC/COFF/cv-fpo-errors.s (added)
+++ llvm/trunk/test/MC/COFF/cv-fpo-errors.s Wed Oct 11 14:24:33 2017
@@ -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

Added: llvm/trunk/test/MC/COFF/cv-fpo-setframe.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/COFF/cv-fpo-setframe.s?rev=315513&view=auto
==============================================================================
--- llvm/trunk/test/MC/COFF/cv-fpo-setframe.s (added)
+++ llvm/trunk/test/MC/COFF/cv-fpo-setframe.s Wed Oct 11 14:24:33 2017
@@ -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




More information about the llvm-commits mailing list