summaryrefslogtreecommitdiffstats
path: root/llvm/test
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/test')
-rw-r--r--llvm/test/DebugInfo/COFF/asan-module-ctor.ll2
-rw-r--r--llvm/test/DebugInfo/COFF/fpo-argsize.ll454
-rw-r--r--llvm/test/DebugInfo/COFF/fpo-csrs.ll559
-rw-r--r--llvm/test/DebugInfo/COFF/fpo-realign-alloca.ll110
-rw-r--r--llvm/test/DebugInfo/COFF/fpo-shrink-wrap.ll154
-rw-r--r--llvm/test/DebugInfo/COFF/fpo-stack-protect.ll114
-rw-r--r--llvm/test/DebugInfo/COFF/multifunction.ll16
-rw-r--r--llvm/test/DebugInfo/COFF/simple.ll17
-rw-r--r--llvm/test/MC/COFF/cv-fpo-csrs.s141
-rw-r--r--llvm/test/MC/COFF/cv-fpo-errors.s47
-rw-r--r--llvm/test/MC/COFF/cv-fpo-setframe.s144
11 files changed, 1753 insertions, 5 deletions
diff --git a/llvm/test/DebugInfo/COFF/asan-module-ctor.ll b/llvm/test/DebugInfo/COFF/asan-module-ctor.ll
index ec495647a89..31e68adfb56 100644
--- a/llvm/test/DebugInfo/COFF/asan-module-ctor.ll
+++ b/llvm/test/DebugInfo/COFF/asan-module-ctor.ll
@@ -10,7 +10,7 @@
; The module ctor has no debug info. All we have to do is don't crash.
; X86: _asan.module_ctor:
; X86-NEXT: L{{.*}}:
-; X86-NEXT: # BB
+; X86: # BB
; X86-NEXT: calll ___asan_init_v3
; X86-NEXT: retl
diff --git a/llvm/test/DebugInfo/COFF/fpo-argsize.ll b/llvm/test/DebugInfo/COFF/fpo-argsize.ll
new file mode 100644
index 00000000000..53b2e5d34b5
--- /dev/null
+++ b/llvm/test/DebugInfo/COFF/fpo-argsize.ll
@@ -0,0 +1,454 @@
+; RUN: llc < %s | grep cv_fpo_proc | FileCheck %s
+
+; C++ source:
+; extern "C" {
+; extern int g;
+;
+; void cdecl1(int a) { g += a; }
+; void cdecl2(int a, int b) { g += a + b; }
+; void cdecl3(int a, int b, int c) { g += a + b + c; }
+;
+; void __fastcall fastcall1(int a) { g += a; }
+; void __fastcall fastcall2(int a, int b) { g += a + b; }
+; void __fastcall fastcall3(int a, int b, int c) { g += a + b + c; }
+;
+; void __stdcall stdcall1(int a) { g += a; }
+; void __stdcall stdcall2(int a, int b) { g += a + b; }
+; void __stdcall stdcall3(int a, int b, int c) { g += a + b + c; }
+; }
+;
+; struct Foo {
+; void thiscall1(int a);
+; void thiscall2(int a, int b);
+; void thiscall3(int a, int b, int c);
+; };
+;
+; void Foo::thiscall1(int a) { g += a; }
+; void Foo::thiscall2(int a, int b) { g += a + b; }
+; void Foo::thiscall3(int a, int b, int c) { g += a + b + c; }
+
+; CHECK: .cv_fpo_proc _cdecl1 4
+; CHECK: .cv_fpo_proc _cdecl2 8
+; CHECK: .cv_fpo_proc _cdecl3 12
+
+; First two args are in registers and don't count.
+; CHECK: .cv_fpo_proc @fastcall1@4 0
+; CHECK: .cv_fpo_proc @fastcall2@8 0
+; CHECK: .cv_fpo_proc @fastcall3@12 4
+
+; CHECK: .cv_fpo_proc _stdcall1@4 4
+; CHECK: .cv_fpo_proc _stdcall2@8 8
+; CHECK: .cv_fpo_proc _stdcall3@12 12
+
+; 'this' is in ecx and doesn't count.
+; CHECK: .cv_fpo_proc "?thiscall1@Foo@@QAEXH@Z" 4
+; CHECK: .cv_fpo_proc "?thiscall2@Foo@@QAEXHH@Z" 8
+; CHECK: .cv_fpo_proc "?thiscall3@Foo@@QAEXHHH@Z" 12
+
+; ModuleID = 't.c'
+source_filename = "t.c"
+target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+target triple = "i386-pc-windows-msvc19.11.25508"
+
+%struct.Foo = type { i8 }
+
+@g = external global i32, align 4
+
+; Function Attrs: noinline nounwind optnone
+define void @cdecl1(i32 %a) #0 !dbg !8 {
+entry:
+ %a.addr = alloca i32, align 4
+ store i32 %a, i32* %a.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !12, metadata !DIExpression()), !dbg !13
+ %0 = load i32, i32* %a.addr, align 4, !dbg !14
+ %1 = load i32, i32* @g, align 4, !dbg !15
+ %add = add nsw i32 %1, %0, !dbg !15
+ store i32 %add, i32* @g, align 4, !dbg !15
+ ret void, !dbg !16
+}
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: noinline nounwind optnone
+define void @cdecl2(i32 %a, i32 %b) #0 !dbg !17 {
+entry:
+ %b.addr = alloca i32, align 4
+ %a.addr = alloca i32, align 4
+ store i32 %b, i32* %b.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !20, metadata !DIExpression()), !dbg !21
+ store i32 %a, i32* %a.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !22, metadata !DIExpression()), !dbg !23
+ %0 = load i32, i32* %a.addr, align 4, !dbg !24
+ %1 = load i32, i32* %b.addr, align 4, !dbg !25
+ %add = add nsw i32 %0, %1, !dbg !26
+ %2 = load i32, i32* @g, align 4, !dbg !27
+ %add1 = add nsw i32 %2, %add, !dbg !27
+ store i32 %add1, i32* @g, align 4, !dbg !27
+ ret void, !dbg !28
+}
+
+; Function Attrs: noinline nounwind optnone
+define void @cdecl3(i32 %a, i32 %b, i32 %c) #0 !dbg !29 {
+entry:
+ %c.addr = alloca i32, align 4
+ %b.addr = alloca i32, align 4
+ %a.addr = alloca i32, align 4
+ store i32 %c, i32* %c.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %c.addr, metadata !32, metadata !DIExpression()), !dbg !33
+ store i32 %b, i32* %b.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !34, metadata !DIExpression()), !dbg !35
+ store i32 %a, i32* %a.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !36, metadata !DIExpression()), !dbg !37
+ %0 = load i32, i32* %a.addr, align 4, !dbg !38
+ %1 = load i32, i32* %b.addr, align 4, !dbg !39
+ %add = add nsw i32 %0, %1, !dbg !40
+ %2 = load i32, i32* %c.addr, align 4, !dbg !41
+ %add1 = add nsw i32 %add, %2, !dbg !42
+ %3 = load i32, i32* @g, align 4, !dbg !43
+ %add2 = add nsw i32 %3, %add1, !dbg !43
+ store i32 %add2, i32* @g, align 4, !dbg !43
+ ret void, !dbg !44
+}
+
+; Function Attrs: noinline nounwind optnone
+define x86_fastcallcc void @"\01@fastcall1@4"(i32 inreg %a) #0 !dbg !45 {
+entry:
+ %a.addr = alloca i32, align 4
+ store i32 %a, i32* %a.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !47, metadata !DIExpression()), !dbg !48
+ %0 = load i32, i32* %a.addr, align 4, !dbg !49
+ %1 = load i32, i32* @g, align 4, !dbg !50
+ %add = add nsw i32 %1, %0, !dbg !50
+ store i32 %add, i32* @g, align 4, !dbg !50
+ ret void, !dbg !51
+}
+
+; Function Attrs: noinline nounwind optnone
+define x86_fastcallcc void @"\01@fastcall2@8"(i32 inreg %a, i32 inreg %b) #0 !dbg !52 {
+entry:
+ %b.addr = alloca i32, align 4
+ %a.addr = alloca i32, align 4
+ store i32 %b, i32* %b.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !54, metadata !DIExpression()), !dbg !55
+ store i32 %a, i32* %a.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !56, metadata !DIExpression()), !dbg !57
+ %0 = load i32, i32* %a.addr, align 4, !dbg !58
+ %1 = load i32, i32* %b.addr, align 4, !dbg !59
+ %add = add nsw i32 %0, %1, !dbg !60
+ %2 = load i32, i32* @g, align 4, !dbg !61
+ %add1 = add nsw i32 %2, %add, !dbg !61
+ store i32 %add1, i32* @g, align 4, !dbg !61
+ ret void, !dbg !62
+}
+
+; Function Attrs: noinline nounwind optnone
+define x86_fastcallcc void @"\01@fastcall3@12"(i32 inreg %a, i32 inreg %b, i32 %c) #0 !dbg !63 {
+entry:
+ %c.addr = alloca i32, align 4
+ %b.addr = alloca i32, align 4
+ %a.addr = alloca i32, align 4
+ store i32 %c, i32* %c.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %c.addr, metadata !65, metadata !DIExpression()), !dbg !66
+ store i32 %b, i32* %b.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !67, metadata !DIExpression()), !dbg !68
+ store i32 %a, i32* %a.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !69, metadata !DIExpression()), !dbg !70
+ %0 = load i32, i32* %a.addr, align 4, !dbg !71
+ %1 = load i32, i32* %b.addr, align 4, !dbg !72
+ %add = add nsw i32 %0, %1, !dbg !73
+ %2 = load i32, i32* %c.addr, align 4, !dbg !74
+ %add1 = add nsw i32 %add, %2, !dbg !75
+ %3 = load i32, i32* @g, align 4, !dbg !76
+ %add2 = add nsw i32 %3, %add1, !dbg !76
+ store i32 %add2, i32* @g, align 4, !dbg !76
+ ret void, !dbg !77
+}
+
+; Function Attrs: noinline nounwind optnone
+define x86_stdcallcc void @"\01_stdcall1@4"(i32 %a) #0 !dbg !78 {
+entry:
+ %a.addr = alloca i32, align 4
+ store i32 %a, i32* %a.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !80, metadata !DIExpression()), !dbg !81
+ %0 = load i32, i32* %a.addr, align 4, !dbg !82
+ %1 = load i32, i32* @g, align 4, !dbg !83
+ %add = add nsw i32 %1, %0, !dbg !83
+ store i32 %add, i32* @g, align 4, !dbg !83
+ ret void, !dbg !84
+}
+
+; Function Attrs: noinline nounwind optnone
+define x86_stdcallcc void @"\01_stdcall2@8"(i32 %a, i32 %b) #0 !dbg !85 {
+entry:
+ %b.addr = alloca i32, align 4
+ %a.addr = alloca i32, align 4
+ store i32 %b, i32* %b.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !87, metadata !DIExpression()), !dbg !88
+ store i32 %a, i32* %a.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !89, metadata !DIExpression()), !dbg !90
+ %0 = load i32, i32* %a.addr, align 4, !dbg !91
+ %1 = load i32, i32* %b.addr, align 4, !dbg !92
+ %add = add nsw i32 %0, %1, !dbg !93
+ %2 = load i32, i32* @g, align 4, !dbg !94
+ %add1 = add nsw i32 %2, %add, !dbg !94
+ store i32 %add1, i32* @g, align 4, !dbg !94
+ ret void, !dbg !95
+}
+
+; Function Attrs: noinline nounwind optnone
+define x86_stdcallcc void @"\01_stdcall3@12"(i32 %a, i32 %b, i32 %c) #0 !dbg !96 {
+entry:
+ %c.addr = alloca i32, align 4
+ %b.addr = alloca i32, align 4
+ %a.addr = alloca i32, align 4
+ store i32 %c, i32* %c.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %c.addr, metadata !98, metadata !DIExpression()), !dbg !99
+ store i32 %b, i32* %b.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !100, metadata !DIExpression()), !dbg !101
+ store i32 %a, i32* %a.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !102, metadata !DIExpression()), !dbg !103
+ %0 = load i32, i32* %a.addr, align 4, !dbg !104
+ %1 = load i32, i32* %b.addr, align 4, !dbg !105
+ %add = add nsw i32 %0, %1, !dbg !106
+ %2 = load i32, i32* %c.addr, align 4, !dbg !107
+ %add1 = add nsw i32 %add, %2, !dbg !108
+ %3 = load i32, i32* @g, align 4, !dbg !109
+ %add2 = add nsw i32 %3, %add1, !dbg !109
+ store i32 %add2, i32* @g, align 4, !dbg !109
+ ret void, !dbg !110
+}
+
+; Function Attrs: noinline nounwind optnone
+define x86_thiscallcc void @"\01?thiscall1@Foo@@QAEXH@Z"(%struct.Foo* %this, i32 %a) #0 align 2 !dbg !111 {
+entry:
+ %a.addr = alloca i32, align 4
+ %this.addr = alloca %struct.Foo*, align 4
+ store i32 %a, i32* %a.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !124, metadata !DIExpression()), !dbg !125
+ store %struct.Foo* %this, %struct.Foo** %this.addr, align 4
+ call void @llvm.dbg.declare(metadata %struct.Foo** %this.addr, metadata !126, metadata !DIExpression()), !dbg !128
+ %this1 = load %struct.Foo*, %struct.Foo** %this.addr, align 4
+ %0 = load i32, i32* %a.addr, align 4, !dbg !129
+ %1 = load i32, i32* @g, align 4, !dbg !130
+ %add = add nsw i32 %1, %0, !dbg !130
+ store i32 %add, i32* @g, align 4, !dbg !130
+ ret void, !dbg !131
+}
+
+; Function Attrs: noinline nounwind optnone
+define x86_thiscallcc void @"\01?thiscall2@Foo@@QAEXHH@Z"(%struct.Foo* %this, i32 %a, i32 %b) #0 align 2 !dbg !132 {
+entry:
+ %b.addr = alloca i32, align 4
+ %a.addr = alloca i32, align 4
+ %this.addr = alloca %struct.Foo*, align 4
+ store i32 %b, i32* %b.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !133, metadata !DIExpression()), !dbg !134
+ store i32 %a, i32* %a.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !135, metadata !DIExpression()), !dbg !136
+ store %struct.Foo* %this, %struct.Foo** %this.addr, align 4
+ call void @llvm.dbg.declare(metadata %struct.Foo** %this.addr, metadata !137, metadata !DIExpression()), !dbg !138
+ %this1 = load %struct.Foo*, %struct.Foo** %this.addr, align 4
+ %0 = load i32, i32* %a.addr, align 4, !dbg !139
+ %1 = load i32, i32* %b.addr, align 4, !dbg !140
+ %add = add nsw i32 %0, %1, !dbg !141
+ %2 = load i32, i32* @g, align 4, !dbg !142
+ %add2 = add nsw i32 %2, %add, !dbg !142
+ store i32 %add2, i32* @g, align 4, !dbg !142
+ ret void, !dbg !143
+}
+
+; Function Attrs: noinline nounwind optnone
+define x86_thiscallcc void @"\01?thiscall3@Foo@@QAEXHHH@Z"(%struct.Foo* %this, i32 %a, i32 %b, i32 %c) #0 align 2 !dbg !144 {
+entry:
+ %c.addr = alloca i32, align 4
+ %b.addr = alloca i32, align 4
+ %a.addr = alloca i32, align 4
+ %this.addr = alloca %struct.Foo*, align 4
+ store i32 %c, i32* %c.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %c.addr, metadata !145, metadata !DIExpression()), !dbg !146
+ store i32 %b, i32* %b.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %b.addr, metadata !147, metadata !DIExpression()), !dbg !148
+ store i32 %a, i32* %a.addr, align 4
+ call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !149, metadata !DIExpression()), !dbg !150
+ store %struct.Foo* %this, %struct.Foo** %this.addr, align 4
+ call void @llvm.dbg.declare(metadata %struct.Foo** %this.addr, metadata !151, metadata !DIExpression()), !dbg !152
+ %this1 = load %struct.Foo*, %struct.Foo** %this.addr, align 4
+ %0 = load i32, i32* %a.addr, align 4, !dbg !153
+ %1 = load i32, i32* %b.addr, align 4, !dbg !154
+ %add = add nsw i32 %0, %1, !dbg !155
+ %2 = load i32, i32* %c.addr, align 4, !dbg !156
+ %add2 = add nsw i32 %add, %2, !dbg !157
+ %3 = load i32, i32* @g, align 4, !dbg !158
+ %add3 = add nsw i32 %3, %add2, !dbg !158
+ store i32 %add3, i32* @g, align 4, !dbg !158
+ ret void, !dbg !159
+}
+
+attributes #0 = { noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone speculatable }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 6.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "t.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "0ce3e4edcf2f8511157da4edb99fcdf4")
+!2 = !{}
+!3 = !{i32 1, !"NumRegisterParameters", i32 0}
+!4 = !{i32 2, !"CodeView", i32 1}
+!5 = !{i32 2, !"Debug Info Version", i32 3}
+!6 = !{i32 1, !"wchar_size", i32 2}
+!7 = !{!"clang version 6.0.0 "}
+!8 = distinct !DISubprogram(name: "cdecl1", scope: !1, file: !1, line: 4, type: !9, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!9 = !DISubroutineType(types: !10)
+!10 = !{null, !11}
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 4, type: !11)
+!13 = !DILocation(line: 4, column: 17, scope: !8)
+!14 = !DILocation(line: 4, column: 27, scope: !8)
+!15 = !DILocation(line: 4, column: 24, scope: !8)
+!16 = !DILocation(line: 4, column: 30, scope: !8)
+!17 = distinct !DISubprogram(name: "cdecl2", scope: !1, file: !1, line: 5, type: !18, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!18 = !DISubroutineType(types: !19)
+!19 = !{null, !11, !11}
+!20 = !DILocalVariable(name: "b", arg: 2, scope: !17, file: !1, line: 5, type: !11)
+!21 = !DILocation(line: 5, column: 24, scope: !17)
+!22 = !DILocalVariable(name: "a", arg: 1, scope: !17, file: !1, line: 5, type: !11)
+!23 = !DILocation(line: 5, column: 17, scope: !17)
+!24 = !DILocation(line: 5, column: 34, scope: !17)
+!25 = !DILocation(line: 5, column: 38, scope: !17)
+!26 = !DILocation(line: 5, column: 36, scope: !17)
+!27 = !DILocation(line: 5, column: 31, scope: !17)
+!28 = !DILocation(line: 5, column: 41, scope: !17)
+!29 = distinct !DISubprogram(name: "cdecl3", scope: !1, file: !1, line: 6, type: !30, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!30 = !DISubroutineType(types: !31)
+!31 = !{null, !11, !11, !11}
+!32 = !DILocalVariable(name: "c", arg: 3, scope: !29, file: !1, line: 6, type: !11)
+!33 = !DILocation(line: 6, column: 31, scope: !29)
+!34 = !DILocalVariable(name: "b", arg: 2, scope: !29, file: !1, line: 6, type: !11)
+!35 = !DILocation(line: 6, column: 24, scope: !29)
+!36 = !DILocalVariable(name: "a", arg: 1, scope: !29, file: !1, line: 6, type: !11)
+!37 = !DILocation(line: 6, column: 17, scope: !29)
+!38 = !DILocation(line: 6, column: 41, scope: !29)
+!39 = !DILocation(line: 6, column: 45, scope: !29)
+!40 = !DILocation(line: 6, column: 43, scope: !29)
+!41 = !DILocation(line: 6, column: 49, scope: !29)
+!42 = !DILocation(line: 6, column: 47, scope: !29)
+!43 = !DILocation(line: 6, column: 38, scope: !29)
+!44 = !DILocation(line: 6, column: 52, scope: !29)
+!45 = distinct !DISubprogram(name: "fastcall1", linkageName: "\01@fastcall1@4", scope: !1, file: !1, line: 8, type: !46, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!46 = !DISubroutineType(cc: DW_CC_BORLAND_msfastcall, types: !10)
+!47 = !DILocalVariable(name: "a", arg: 1, scope: !45, file: !1, line: 8, type: !11)
+!48 = !DILocation(line: 8, column: 31, scope: !45)
+!49 = !DILocation(line: 8, column: 41, scope: !45)
+!50 = !DILocation(line: 8, column: 38, scope: !45)
+!51 = !DILocation(line: 8, column: 44, scope: !45)
+!52 = distinct !DISubprogram(name: "fastcall2", linkageName: "\01@fastcall2@8", scope: !1, file: !1, line: 9, type: !53, isLocal: false, isDefinition: true, scopeLine: 9, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!53 = !DISubroutineType(cc: DW_CC_BORLAND_msfastcall, types: !19)
+!54 = !DILocalVariable(name: "b", arg: 2, scope: !52, file: !1, line: 9, type: !11)
+!55 = !DILocation(line: 9, column: 38, scope: !52)
+!56 = !DILocalVariable(name: "a", arg: 1, scope: !52, file: !1, line: 9, type: !11)
+!57 = !DILocation(line: 9, column: 31, scope: !52)
+!58 = !DILocation(line: 9, column: 48, scope: !52)
+!59 = !DILocation(line: 9, column: 52, scope: !52)
+!60 = !DILocation(line: 9, column: 50, scope: !52)
+!61 = !DILocation(line: 9, column: 45, scope: !52)
+!62 = !DILocation(line: 9, column: 55, scope: !52)
+!63 = distinct !DISubprogram(name: "fastcall3", linkageName: "\01@fastcall3@12", scope: !1, file: !1, line: 10, type: !64, isLocal: false, isDefinition: true, scopeLine: 10, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!64 = !DISubroutineType(cc: DW_CC_BORLAND_msfastcall, types: !31)
+!65 = !DILocalVariable(name: "c", arg: 3, scope: !63, file: !1, line: 10, type: !11)
+!66 = !DILocation(line: 10, column: 45, scope: !63)
+!67 = !DILocalVariable(name: "b", arg: 2, scope: !63, file: !1, line: 10, type: !11)
+!68 = !DILocation(line: 10, column: 38, scope: !63)
+!69 = !DILocalVariable(name: "a", arg: 1, scope: !63, file: !1, line: 10, type: !11)
+!70 = !DILocation(line: 10, column: 31, scope: !63)
+!71 = !DILocation(line: 10, column: 55, scope: !63)
+!72 = !DILocation(line: 10, column: 59, scope: !63)
+!73 = !DILocation(line: 10, column: 57, scope: !63)
+!74 = !DILocation(line: 10, column: 63, scope: !63)
+!75 = !DILocation(line: 10, column: 61, scope: !63)
+!76 = !DILocation(line: 10, column: 52, scope: !63)
+!77 = !DILocation(line: 10, column: 66, scope: !63)
+!78 = distinct !DISubprogram(name: "stdcall1", linkageName: "\01_stdcall1@4", scope: !1, file: !1, line: 12, type: !79, isLocal: false, isDefinition: true, scopeLine: 12, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!79 = !DISubroutineType(cc: DW_CC_BORLAND_stdcall, types: !10)
+!80 = !DILocalVariable(name: "a", arg: 1, scope: !78, file: !1, line: 12, type: !11)
+!81 = !DILocation(line: 12, column: 29, scope: !78)
+!82 = !DILocation(line: 12, column: 39, scope: !78)
+!83 = !DILocation(line: 12, column: 36, scope: !78)
+!84 = !DILocation(line: 12, column: 42, scope: !78)
+!85 = distinct !DISubprogram(name: "stdcall2", linkageName: "\01_stdcall2@8", scope: !1, file: !1, line: 13, type: !86, isLocal: false, isDefinition: true, scopeLine: 13, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!86 = !DISubroutineType(cc: DW_CC_BORLAND_stdcall, types: !19)
+!87 = !DILocalVariable(name: "b", arg: 2, scope: !85, file: !1, line: 13, type: !11)
+!88 = !DILocation(line: 13, column: 36, scope: !85)
+!89 = !DILocalVariable(name: "a", arg: 1, scope: !85, file: !1, line: 13, type: !11)
+!90 = !DILocation(line: 13, column: 29, scope: !85)
+!91 = !DILocation(line: 13, column: 46, scope: !85)
+!92 = !DILocation(line: 13, column: 50, scope: !85)
+!93 = !DILocation(line: 13, column: 48, scope: !85)
+!94 = !DILocation(line: 13, column: 43, scope: !85)
+!95 = !DILocation(line: 13, column: 53, scope: !85)
+!96 = distinct !DISubprogram(name: "stdcall3", linkageName: "\01_stdcall3@12", scope: !1, file: !1, line: 14, type: !97, isLocal: false, isDefinition: true, scopeLine: 14, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!97 = !DISubroutineType(cc: DW_CC_BORLAND_stdcall, types: !31)
+!98 = !DILocalVariable(name: "c", arg: 3, scope: !96, file: !1, line: 14, type: !11)
+!99 = !DILocation(line: 14, column: 43, scope: !96)
+!100 = !DILocalVariable(name: "b", arg: 2, scope: !96, file: !1, line: 14, type: !11)
+!101 = !DILocation(line: 14, column: 36, scope: !96)
+!102 = !DILocalVariable(name: "a", arg: 1, scope: !96, file: !1, line: 14, type: !11)
+!103 = !DILocation(line: 14, column: 29, scope: !96)
+!104 = !DILocation(line: 14, column: 53, scope: !96)
+!105 = !DILocation(line: 14, column: 57, scope: !96)
+!106 = !DILocation(line: 14, column: 55, scope: !96)
+!107 = !DILocation(line: 14, column: 61, scope: !96)
+!108 = !DILocation(line: 14, column: 59, scope: !96)
+!109 = !DILocation(line: 14, column: 50, scope: !96)
+!110 = !DILocation(line: 14, column: 64, scope: !96)
+!111 = distinct !DISubprogram(name: "thiscall1", linkageName: "\01?thiscall1@Foo@@QAEXH@Z", scope: !112, file: !1, line: 23, type: !115, isLocal: false, isDefinition: true, scopeLine: 23, flags: DIFlagPrototyped, isOptimized: false, unit: !0, declaration: !114, variables: !2)
+!112 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", file: !1, line: 17, size: 8, elements: !113, identifier: ".?AUFoo@@")
+!113 = !{!114, !118, !121}
+!114 = !DISubprogram(name: "thiscall1", linkageName: "\01?thiscall1@Foo@@QAEXH@Z", scope: !112, file: !1, line: 18, type: !115, isLocal: false, isDefinition: false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false)
+!115 = !DISubroutineType(cc: DW_CC_BORLAND_thiscall, types: !116)
+!116 = !{null, !117, !11}
+!117 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !112, size: 32, flags: DIFlagArtificial | DIFlagObjectPointer)
+!118 = !DISubprogram(name: "thiscall2", linkageName: "\01?thiscall2@Foo@@QAEXHH@Z", scope: !112, file: !1, line: 19, type: !119, isLocal: false, isDefinition: false, scopeLine: 19, flags: DIFlagPrototyped, isOptimized: false)
+!119 = !DISubroutineType(cc: DW_CC_BORLAND_thiscall, types: !120)
+!120 = !{null, !117, !11, !11}
+!121 = !DISubprogram(name: "thiscall3", linkageName: "\01?thiscall3@Foo@@QAEXHHH@Z", scope: !112, file: !1, line: 20, type: !122, isLocal: false, isDefinition: false, scopeLine: 20, flags: DIFlagPrototyped, isOptimized: false)
+!122 = !DISubroutineType(cc: DW_CC_BORLAND_thiscall, types: !123)
+!123 = !{null, !117, !11, !11, !11}
+!124 = !DILocalVariable(name: "a", arg: 2, scope: !111, file: !1, line: 23, type: !11)
+!125 = !DILocation(line: 23, column: 25, scope: !111)
+!126 = !DILocalVariable(name: "this", arg: 1, scope: !111, type: !127, flags: DIFlagArtificial | DIFlagObjectPointer)
+!127 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !112, size: 32)
+!128 = !DILocation(line: 0, scope: !111)
+!129 = !DILocation(line: 23, column: 35, scope: !111)
+!130 = !DILocation(line: 23, column: 32, scope: !111)
+!131 = !DILocation(line: 23, column: 38, scope: !111)
+!132 = distinct !DISubprogram(name: "thiscall2", linkageName: "\01?thiscall2@Foo@@QAEXHH@Z", scope: !112, file: !1, line: 24, type: !119, isLocal: false, isDefinition: true, scopeLine: 24, flags: DIFlagPrototyped, isOptimized: false, unit: !0, declaration: !118, variables: !2)
+!133 = !DILocalVariable(name: "b", arg: 3, scope: !132, file: !1, line: 24, type: !11)
+!134 = !DILocation(line: 24, column: 32, scope: !132)
+!135 = !DILocalVariable(name: "a", arg: 2, scope: !132, file: !1, line: 24, type: !11)
+!136 = !DILocation(line: 24, column: 25, scope: !132)
+!137 = !DILocalVariable(name: "this", arg: 1, scope: !132, type: !127, flags: DIFlagArtificial | DIFlagObjectPointer)
+!138 = !DILocation(line: 0, scope: !132)
+!139 = !DILocation(line: 24, column: 42, scope: !132)
+!140 = !DILocation(line: 24, column: 46, scope: !132)
+!141 = !DILocation(line: 24, column: 44, scope: !132)
+!142 = !DILocation(line: 24, column: 39, scope: !132)
+!143 = !DILocation(line: 24, column: 49, scope: !132)
+!144 = distinct !DISubprogram(name: "thiscall3", linkageName: "\01?thiscall3@Foo@@QAEXHHH@Z", scope: !112, file: !1, line: 25, type: !122, isLocal: false, isDefinition: true, scopeLine: 25, flags: DIFlagPrototyped, isOptimized: false, unit: !0, declaration: !121, variables: !2)
+!145 = !DILocalVariable(name: "c", arg: 4, scope: !144, file: !1, line: 25, type: !11)
+!146 = !DILocation(line: 25, column: 39, scope: !144)
+!147 = !DILocalVariable(name: "b", arg: 3, scope: !144, file: !1, line: 25, type: !11)
+!148 = !DILocation(line: 25, column: 32, scope: !144)
+!149 = !DILocalVariable(name: "a", arg: 2, scope: !144, file: !1, line: 25, type: !11)
+!150 = !DILocation(line: 25, column: 25, scope: !144)
+!151 = !DILocalVariable(name: "this", arg: 1, scope: !144, type: !127, flags: DIFlagArtificial | DIFlagObjectPointer)
+!152 = !DILocation(line: 0, scope: !144)
+!153 = !DILocation(line: 25, column: 49, scope: !144)
+!154 = !DILocation(line: 25, column: 53, scope: !144)
+!155 = !DILocation(line: 25, column: 51, scope: !144)
+!156 = !DILocation(line: 25, column: 57, scope: !144)
+!157 = !DILocation(line: 25, column: 55, scope: !144)
+!158 = !DILocation(line: 25, column: 46, scope: !144)
+!159 = !DILocation(line: 25, column: 60, scope: !144)
diff --git a/llvm/test/DebugInfo/COFF/fpo-csrs.ll b/llvm/test/DebugInfo/COFF/fpo-csrs.ll
new file mode 100644
index 00000000000..5c5ca888d14
--- /dev/null
+++ b/llvm/test/DebugInfo/COFF/fpo-csrs.ll
@@ -0,0 +1,559 @@
+; RUN: llc < %s | FileCheck %s --check-prefix=ASM
+; RUN: llc -filetype=obj < %s | llvm-readobj -codeview | FileCheck %s --check-prefix=OBJ
+
+; C source:
+; int getval(void);
+; void usevals(int, ...);
+; int csr1() {
+; int a = getval();
+; usevals(a);
+; usevals(a);
+; return a;
+; }
+; int csr2() {
+; int a = getval();
+; int b = getval();
+; usevals(a, b);
+; usevals(a, b);
+; return a;
+; }
+; int csr3() {
+; int a = getval();
+; int b = getval();
+; int c = getval();
+; usevals(a, b, c);
+; usevals(a, b, c);
+; return a;
+; }
+; int csr4() {
+; int a = getval();
+; int b = getval();
+; int c = getval();
+; int d = getval();
+; usevals(a, b, c, d);
+; usevals(a, b, c, d);
+; return a;
+; }
+; int spill() {
+; int a = getval();
+; int b = getval();
+; int c = getval();
+; int d = getval();
+; int e = getval();
+; usevals(a, b, c, d, e);
+; usevals(a, b, c, d, e);
+; return a;
+; }
+
+; ModuleID = 't.c'
+source_filename = "t.c"
+target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+target triple = "i386-pc-windows-msvc19.11.25508"
+
+; Function Attrs: nounwind
+define i32 @csr1() local_unnamed_addr #0 !dbg !8 {
+entry:
+ %call = tail call i32 @getval() #3, !dbg !14
+ tail call void @llvm.dbg.value(metadata i32 %call, metadata !13, metadata !DIExpression()), !dbg !15
+ tail call void (i32, ...) @usevals(i32 %call) #3, !dbg !16
+ tail call void (i32, ...) @usevals(i32 %call) #3, !dbg !17
+ ret i32 %call, !dbg !18
+}
+
+; ASM-LABEL: _csr1: # @csr1
+; ASM: .cv_fpo_proc _csr1
+; ASM: pushl %esi
+; ASM: .cv_fpo_pushreg %esi
+; ASM: .cv_fpo_endprologue
+; ASM: #DEBUG_VALUE: csr1:a <- %ESI
+; ASM: retl
+; ASM: .cv_fpo_endproc
+
+; OBJ-LABEL: SubSectionType: FrameData (0xF5)
+; OBJ-NEXT: SubSectionSize:
+; OBJ-NEXT: LinkageName: _csr1
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT: RvaStart: 0x0
+; OBJ-NEXT: CodeSize: 0x1E
+; OBJ-NEXT: LocalSize: 0x0
+; OBJ-NEXT: ParamsSize: 0x0
+; OBJ-NEXT: MaxStackSize: 0x0
+; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+; OBJ-NEXT: PrologSize: 0x1
+; OBJ-NEXT: SavedRegsSize: 0x0
+; OBJ-NEXT: Flags [ (0x4)
+; OBJ-NEXT: IsFunctionStart (0x4)
+; OBJ-NEXT: ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT: RvaStart: 0x1
+; OBJ-NEXT: CodeSize: 0x1D
+; OBJ-NEXT: LocalSize: 0x0
+; OBJ-NEXT: ParamsSize: 0x0
+; OBJ-NEXT: MaxStackSize: 0x0
+; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $esi $T0 4 - ^ =
+; OBJ-NEXT: PrologSize: 0x0
+; OBJ-NEXT: SavedRegsSize: 0x4
+; OBJ-NEXT: Flags [ (0x0)
+; OBJ-NEXT: ]
+; OBJ-NEXT: }
+; OBJ-NOT: FrameData
+
+declare i32 @getval() local_unnamed_addr #1
+
+declare void @usevals(i32, ...) local_unnamed_addr #1
+
+; Function Attrs: nounwind
+define i32 @csr2() local_unnamed_addr #0 !dbg !19 {
+entry:
+ %call = tail call i32 @getval() #3, !dbg !23
+ tail call void @llvm.dbg.value(metadata i32 %call, metadata !21, metadata !DIExpression()), !dbg !24
+ %call1 = tail call i32 @getval() #3, !dbg !25
+ tail call void @llvm.dbg.value(metadata i32 %call1, metadata !22, metadata !DIExpression()), !dbg !26
+ tail call void (i32, ...) @usevals(i32 %call, i32 %call1) #3, !dbg !27
+ tail call void (i32, ...) @usevals(i32 %call, i32 %call1) #3, !dbg !28
+ ret i32 %call, !dbg !29
+}
+
+; ASM-LABEL: _csr2: # @csr2
+; ASM: .cv_fpo_proc _csr2
+; ASM: pushl %edi
+; ASM: .cv_fpo_pushreg %edi
+; ASM: pushl %esi
+; ASM: .cv_fpo_pushreg %esi
+; ASM: .cv_fpo_endprologue
+; ASM: #DEBUG_VALUE: csr2:a <- %ESI
+; ASM: #DEBUG_VALUE: csr2:b <- %EDI
+; ASM: retl
+; ASM: .cv_fpo_endproc
+
+; OBJ-LABEL: SubSectionType: FrameData (0xF5)
+; OBJ-NEXT: SubSectionSize:
+; OBJ-NEXT: LinkageName: _csr2
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT: RvaStart: 0x0
+; OBJ-NEXT: CodeSize: 0x29
+; OBJ-NEXT: LocalSize: 0x0
+; OBJ-NEXT: ParamsSize: 0x0
+; OBJ-NEXT: MaxStackSize: 0x0
+; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+; OBJ-NEXT: PrologSize: 0x2
+; OBJ-NEXT: SavedRegsSize: 0x0
+; OBJ-NEXT: Flags [ (0x4)
+; OBJ-NEXT: IsFunctionStart (0x4)
+; OBJ-NEXT: ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT: RvaStart: 0x1
+; OBJ-NEXT: CodeSize: 0x28
+; OBJ-NEXT: LocalSize: 0x0
+; OBJ-NEXT: ParamsSize: 0x0
+; OBJ-NEXT: MaxStackSize: 0x0
+; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $edi $T0 4 - ^ =
+; OBJ-NEXT: PrologSize: 0x1
+; OBJ-NEXT: SavedRegsSize: 0x4
+; OBJ-NEXT: Flags [ (0x0)
+; OBJ-NEXT: ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT: RvaStart: 0x2
+; OBJ-NEXT: CodeSize: 0x27
+; OBJ-NEXT: LocalSize: 0x0
+; OBJ-NEXT: ParamsSize: 0x0
+; OBJ-NEXT: MaxStackSize: 0x0
+; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $edi $T0 4 - ^ = $esi $T0 8 - ^ =
+; OBJ-NEXT: PrologSize: 0x0
+; OBJ-NEXT: SavedRegsSize: 0x8
+; OBJ-NEXT: Flags [ (0x0)
+; OBJ-NEXT: ]
+; OBJ-NEXT: }
+; OBJ-NOT: FrameData
+
+; Function Attrs: nounwind
+define i32 @csr3() local_unnamed_addr #0 !dbg !30 {
+entry:
+ %call = tail call i32 @getval() #3, !dbg !35
+ tail call void @llvm.dbg.value(metadata i32 %call, metadata !32, metadata !DIExpression()), !dbg !36
+ %call1 = tail call i32 @getval() #3, !dbg !37
+ tail call void @llvm.dbg.value(metadata i32 %call1, metadata !33, metadata !DIExpression()), !dbg !38
+ %call2 = tail call i32 @getval() #3, !dbg !39
+ tail call void @llvm.dbg.value(metadata i32 %call2, metadata !34, metadata !DIExpression()), !dbg !40
+ tail call void (i32, ...) @usevals(i32 %call, i32 %call1, i32 %call2) #3, !dbg !41
+ tail call void (i32, ...) @usevals(i32 %call, i32 %call1, i32 %call2) #3, !dbg !42
+ ret i32 %call, !dbg !43
+}
+
+; ASM-LABEL: _csr3: # @csr3
+; ASM: .cv_fpo_proc _csr3
+; ASM: pushl %ebx
+; ASM: .cv_fpo_pushreg %ebx
+; ASM: pushl %edi
+; ASM: .cv_fpo_pushreg %edi
+; ASM: pushl %esi
+; ASM: .cv_fpo_pushreg %esi
+; ASM: .cv_fpo_endprologue
+; ASM: #DEBUG_VALUE: csr3:a <- %ESI
+; ASM: #DEBUG_VALUE: csr3:b <- %EDI
+; ASM: #DEBUG_VALUE: csr3:c <- %EBX
+; ASM: retl
+; ASM: .cv_fpo_endproc
+
+; OBJ-LABEL: SubSectionType: FrameData (0xF5)
+; OBJ-NEXT: SubSectionSize:
+; OBJ-NEXT: LinkageName: _csr3
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT: RvaStart: 0x0
+; OBJ-NEXT: CodeSize: 0x34
+; OBJ-NEXT: LocalSize: 0x0
+; OBJ-NEXT: ParamsSize: 0x0
+; OBJ-NEXT: MaxStackSize: 0x0
+; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+; OBJ-NEXT: PrologSize: 0x3
+; OBJ-NEXT: SavedRegsSize: 0x0
+; OBJ-NEXT: Flags [ (0x4)
+; OBJ-NEXT: IsFunctionStart (0x4)
+; OBJ-NEXT: ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT: RvaStart: 0x1
+; OBJ-NEXT: CodeSize: 0x33
+; OBJ-NEXT: LocalSize: 0x0
+; OBJ-NEXT: ParamsSize: 0x0
+; OBJ-NEXT: MaxStackSize: 0x0
+; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebx $T0 4 - ^ =
+; OBJ-NEXT: PrologSize: 0x2
+; OBJ-NEXT: SavedRegsSize: 0x4
+; OBJ-NEXT: Flags [ (0x0)
+; OBJ-NEXT: ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT: RvaStart: 0x2
+; OBJ-NEXT: CodeSize: 0x32
+; OBJ-NEXT: LocalSize: 0x0
+; OBJ-NEXT: ParamsSize: 0x0
+; OBJ-NEXT: MaxStackSize: 0x0
+; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebx $T0 4 - ^ = $edi $T0 8 - ^ =
+; OBJ-NEXT: PrologSize: 0x1
+; OBJ-NEXT: SavedRegsSize: 0x8
+; OBJ-NEXT: Flags [ (0x0)
+; OBJ-NEXT: ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT: RvaStart: 0x3
+; OBJ-NEXT: CodeSize: 0x31
+; OBJ-NEXT: LocalSize: 0x0
+; OBJ-NEXT: ParamsSize: 0x0
+; OBJ-NEXT: MaxStackSize: 0x0
+; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebx $T0 4 - ^ = $edi $T0 8 - ^ = $esi $T0 12 - ^ =
+; OBJ-NEXT: PrologSize: 0x0
+; OBJ-NEXT: SavedRegsSize: 0xC
+; OBJ-NEXT: Flags [ (0x0)
+; OBJ-NEXT: ]
+; OBJ-NEXT: }
+; OBJ-NOT: FrameData
+
+; Function Attrs: nounwind
+define i32 @csr4() local_unnamed_addr #0 !dbg !44 {
+entry:
+ %call = tail call i32 @getval() #3, !dbg !50
+ tail call void @llvm.dbg.value(metadata i32 %call, metadata !46, metadata !DIExpression()), !dbg !51
+ %call1 = tail call i32 @getval() #3, !dbg !52
+ tail call void @llvm.dbg.value(metadata i32 %call1, metadata !47, metadata !DIExpression()), !dbg !53
+ %call2 = tail call i32 @getval() #3, !dbg !54
+ tail call void @llvm.dbg.value(metadata i32 %call2, metadata !48, metadata !DIExpression()), !dbg !55
+ %call3 = tail call i32 @getval() #3, !dbg !56
+ tail call void @llvm.dbg.value(metadata i32 %call3, metadata !49, metadata !DIExpression()), !dbg !57
+ tail call void (i32, ...) @usevals(i32 %call, i32 %call1, i32 %call2, i32 %call3) #3, !dbg !58
+ tail call void (i32, ...) @usevals(i32 %call, i32 %call1, i32 %call2, i32 %call3) #3, !dbg !59
+ ret i32 %call, !dbg !60
+}
+
+; ASM-LABEL: _csr4: # @csr4
+; ASM: .cv_fpo_proc _csr4
+; ASM: pushl %ebp
+; ASM: .cv_fpo_pushreg %ebp
+; ASM: pushl %ebx
+; ASM: .cv_fpo_pushreg %ebx
+; ASM: pushl %edi
+; ASM: .cv_fpo_pushreg %edi
+; ASM: pushl %esi
+; ASM: .cv_fpo_pushreg %esi
+; ASM: .cv_fpo_endprologue
+; ASM: #DEBUG_VALUE: csr4:a <- %ESI
+; ASM: #DEBUG_VALUE: csr4:b <- %EDI
+; ASM: #DEBUG_VALUE: csr4:c <- %EBX
+; ASM: #DEBUG_VALUE: csr4:d <- %EBP
+; ASM: retl
+; ASM: .cv_fpo_endproc
+
+; OBJ-LABEL: SubSectionType: FrameData (0xF5)
+; OBJ-NEXT: SubSectionSize:
+; OBJ-NEXT: LinkageName: _csr4
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT: RvaStart: 0x0
+; OBJ-NEXT: CodeSize: 0x3F
+; OBJ-NEXT: LocalSize: 0x0
+; OBJ-NEXT: ParamsSize: 0x0
+; OBJ-NEXT: MaxStackSize: 0x0
+; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+; OBJ-NEXT: PrologSize: 0x4
+; OBJ-NEXT: SavedRegsSize: 0x0
+; OBJ-NEXT: Flags [ (0x4)
+; OBJ-NEXT: IsFunctionStart (0x4)
+; OBJ-NEXT: ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT: RvaStart: 0x1
+; OBJ-NEXT: CodeSize: 0x3E
+; OBJ-NEXT: LocalSize: 0x0
+; OBJ-NEXT: ParamsSize: 0x0
+; OBJ-NEXT: MaxStackSize: 0x0
+; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
+; OBJ-NEXT: PrologSize: 0x3
+; OBJ-NEXT: SavedRegsSize: 0x4
+; OBJ-NEXT: Flags [ (0x0)
+; OBJ-NEXT: ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT: RvaStart: 0x2
+; OBJ-NEXT: CodeSize: 0x3D
+; OBJ-NEXT: LocalSize: 0x0
+; OBJ-NEXT: ParamsSize: 0x0
+; OBJ-NEXT: MaxStackSize: 0x0
+; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ =
+; OBJ-NEXT: PrologSize: 0x2
+; OBJ-NEXT: SavedRegsSize: 0x8
+; OBJ-NEXT: Flags [ (0x0)
+; OBJ-NEXT: ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT: RvaStart: 0x3
+; OBJ-NEXT: CodeSize: 0x3C
+; OBJ-NEXT: LocalSize: 0x0
+; OBJ-NEXT: ParamsSize: 0x0
+; OBJ-NEXT: MaxStackSize: 0x0
+; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ =
+; OBJ-NEXT: PrologSize: 0x1
+; OBJ-NEXT: SavedRegsSize: 0xC
+; OBJ-NEXT: Flags [ (0x0)
+; OBJ-NEXT: ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT: RvaStart: 0x4
+; OBJ-NEXT: CodeSize: 0x3B
+; OBJ-NEXT: LocalSize: 0x0
+; OBJ-NEXT: ParamsSize: 0x0
+; OBJ-NEXT: MaxStackSize: 0x0
+; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ = $esi $T0 16 - ^ =
+; OBJ-NEXT: PrologSize: 0x0
+; OBJ-NEXT: SavedRegsSize: 0x10
+; OBJ-NEXT: Flags [ (0x0)
+; OBJ-NEXT: ]
+; OBJ-NEXT: }
+; OBJ-NOT: FrameData
+
+; Function Attrs: nounwind
+define i32 @spill() local_unnamed_addr #0 !dbg !61 {
+entry:
+ %call = tail call i32 @getval() #3, !dbg !68
+ tail call void @llvm.dbg.value(metadata i32 %call, metadata !63, metadata !DIExpression()), !dbg !69
+ %call1 = tail call i32 @getval() #3, !dbg !70
+ tail call void @llvm.dbg.value(metadata i32 %call1, metadata !64, metadata !DIExpression()), !dbg !71
+ %call2 = tail call i32 @getval() #3, !dbg !72
+ tail call void @llvm.dbg.value(metadata i32 %call2, metadata !65, metadata !DIExpression()), !dbg !73
+ %call3 = tail call i32 @getval() #3, !dbg !74
+ tail call void @llvm.dbg.value(metadata i32 %call3, metadata !66, metadata !DIExpression()), !dbg !75
+ %call4 = tail call i32 @getval() #3, !dbg !76
+ tail call void @llvm.dbg.value(metadata i32 %call4, metadata !67, metadata !DIExpression()), !dbg !77
+ tail call void (i32, ...) @usevals(i32 %call, i32 %call1, i32 %call2, i32 %call3, i32 %call4) #3, !dbg !78
+ tail call void (i32, ...) @usevals(i32 %call, i32 %call1, i32 %call2, i32 %call3, i32 %call4) #3, !dbg !79
+ ret i32 %call, !dbg !80
+}
+
+; ASM-LABEL: _spill: # @spill
+; ASM: .cv_fpo_proc _spill
+; ASM: pushl %ebp
+; ASM: .cv_fpo_pushreg %ebp
+; ASM: pushl %ebx
+; ASM: .cv_fpo_pushreg %ebx
+; ASM: pushl %edi
+; ASM: .cv_fpo_pushreg %edi
+; ASM: pushl %esi
+; ASM: .cv_fpo_pushreg %esi
+; ASM: subl $8, %esp
+; ASM: .cv_fpo_stackalloc 8
+; ASM: .cv_fpo_endprologue
+; ASM: retl
+; ASM: .cv_fpo_endproc
+
+; OBJ-LABEL: SubSectionType: FrameData (0xF5)
+; OBJ-NEXT: SubSectionSize:
+; OBJ-NEXT: LinkageName: _spill
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT: RvaStart: 0x0
+; OBJ-NEXT: CodeSize: 0x5A
+; OBJ-NEXT: LocalSize: 0x0
+; OBJ-NEXT: ParamsSize: 0x0
+; OBJ-NEXT: MaxStackSize: 0x0
+; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+; OBJ-NEXT: PrologSize: 0x7
+; OBJ-NEXT: SavedRegsSize: 0x0
+; OBJ-NEXT: Flags [ (0x4)
+; OBJ-NEXT: IsFunctionStart (0x4)
+; OBJ-NEXT: ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT: RvaStart: 0x1
+; OBJ-NEXT: CodeSize: 0x59
+; OBJ-NEXT: LocalSize: 0x0
+; OBJ-NEXT: ParamsSize: 0x0
+; OBJ-NEXT: MaxStackSize: 0x0
+; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
+; OBJ-NEXT: PrologSize: 0x6
+; OBJ-NEXT: SavedRegsSize: 0x4
+; OBJ-NEXT: Flags [ (0x0)
+; OBJ-NEXT: ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT: RvaStart: 0x2
+; OBJ-NEXT: CodeSize: 0x58
+; OBJ-NEXT: LocalSize: 0x0
+; OBJ-NEXT: ParamsSize: 0x0
+; OBJ-NEXT: MaxStackSize: 0x0
+; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ =
+; OBJ-NEXT: PrologSize: 0x5
+; OBJ-NEXT: SavedRegsSize: 0x8
+; OBJ-NEXT: Flags [ (0x0)
+; OBJ-NEXT: ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT: RvaStart: 0x3
+; OBJ-NEXT: CodeSize: 0x57
+; OBJ-NEXT: LocalSize: 0x0
+; OBJ-NEXT: ParamsSize: 0x0
+; OBJ-NEXT: MaxStackSize: 0x0
+; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ =
+; OBJ-NEXT: PrologSize: 0x4
+; OBJ-NEXT: SavedRegsSize: 0xC
+; OBJ-NEXT: Flags [ (0x0)
+; OBJ-NEXT: ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT: RvaStart: 0x4
+; OBJ-NEXT: CodeSize: 0x56
+; OBJ-NEXT: LocalSize: 0x0
+; OBJ-NEXT: ParamsSize: 0x0
+; OBJ-NEXT: MaxStackSize: 0x0
+; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ = $esi $T0 16 - ^ =
+; OBJ-NEXT: PrologSize: 0x3
+; OBJ-NEXT: SavedRegsSize: 0x10
+; OBJ-NEXT: Flags [ (0x0)
+; OBJ-NEXT: ]
+; OBJ-NEXT: }
+; OBJ-NEXT: FrameData {
+; OBJ-NEXT: RvaStart: 0x7
+; OBJ-NEXT: CodeSize: 0x53
+; OBJ-NEXT: LocalSize: 0x8
+; OBJ-NEXT: ParamsSize: 0x0
+; OBJ-NEXT: MaxStackSize: 0x0
+; OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ = $esi $T0 16 - ^ =
+; OBJ-NEXT: PrologSize: 0x0
+; OBJ-NEXT: SavedRegsSize: 0x10
+; OBJ-NEXT: Flags [ (0x0)
+; OBJ-NEXT: ]
+; OBJ-NEXT: }
+; OBJ-NOT: FrameData
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone speculatable }
+attributes #3 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "t.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "0b1c85f8a0bfb41380df1fcaeadde306")
+!2 = !{}
+!3 = !{i32 1, !"NumRegisterParameters", i32 0}
+!4 = !{i32 2, !"CodeView", i32 1}
+!5 = !{i32 2, !"Debug Info Version", i32 3}
+!6 = !{i32 1, !"wchar_size", i32 2}
+!7 = !{!"clang version 6.0.0 "}
+!8 = distinct !DISubprogram(name: "csr1", scope: !1, file: !1, line: 3, type: !9, isLocal: false, isDefinition: true, scopeLine: 3, isOptimized: true, unit: !0, variables: !12)
+!9 = !DISubroutineType(types: !10)
+!10 = !{!11}
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !{!13}
+!13 = !DILocalVariable(name: "a", scope: !8, file: !1, line: 4, type: !11)
+!14 = !DILocation(line: 4, column: 11, scope: !8)
+!15 = !DILocation(line: 4, column: 7, scope: !8)
+!16 = !DILocation(line: 5, column: 3, scope: !8)
+!17 = !DILocation(line: 6, column: 3, scope: !8)
+!18 = !DILocation(line: 7, column: 3, scope: !8)
+!19 = distinct !DISubprogram(name: "csr2", scope: !1, file: !1, line: 9, type: !9, isLocal: false, isDefinition: true, scopeLine: 9, isOptimized: true, unit: !0, variables: !20)
+!20 = !{!21, !22}
+!21 = !DILocalVariable(name: "a", scope: !19, file: !1, line: 10, type: !11)
+!22 = !DILocalVariable(name: "b", scope: !19, file: !1, line: 11, type: !11)
+!23 = !DILocation(line: 10, column: 11, scope: !19)
+!24 = !DILocation(line: 10, column: 7, scope: !19)
+!25 = !DILocation(line: 11, column: 11, scope: !19)
+!26 = !DILocation(line: 11, column: 7, scope: !19)
+!27 = !DILocation(line: 12, column: 3, scope: !19)
+!28 = !DILocation(line: 13, column: 3, scope: !19)
+!29 = !DILocation(line: 14, column: 3, scope: !19)
+!30 = distinct !DISubprogram(name: "csr3", scope: !1, file: !1, line: 16, type: !9, isLocal: false, isDefinition: true, scopeLine: 16, isOptimized: true, unit: !0, variables: !31)
+!31 = !{!32, !33, !34}
+!32 = !DILocalVariable(name: "a", scope: !30, file: !1, line: 17, type: !11)
+!33 = !DILocalVariable(name: "b", scope: !30, file: !1, line: 18, type: !11)
+!34 = !DILocalVariable(name: "c", scope: !30, file: !1, line: 19, type: !11)
+!35 = !DILocation(line: 17, column: 11, scope: !30)
+!36 = !DILocation(line: 17, column: 7, scope: !30)
+!37 = !DILocation(line: 18, column: 11, scope: !30)
+!38 = !DILocation(line: 18, column: 7, scope: !30)
+!39 = !DILocation(line: 19, column: 11, scope: !30)
+!40 = !DILocation(line: 19, column: 7, scope: !30)
+!41 = !DILocation(line: 20, column: 3, scope: !30)
+!42 = !DILocation(line: 21, column: 3, scope: !30)
+!43 = !DILocation(line: 22, column: 3, scope: !30)
+!44 = distinct !DISubprogram(name: "csr4", scope: !1, file: !1, line: 24, type: !9, isLocal: false, isDefinition: true, scopeLine: 24, isOptimized: true, unit: !0, variables: !45)
+!45 = !{!46, !47, !48, !49}
+!46 = !DILocalVariable(name: "a", scope: !44, file: !1, line: 25, type: !11)
+!47 = !DILocalVariable(name: "b", scope: !44, file: !1, line: 26, type: !11)
+!48 = !DILocalVariable(name: "c", scope: !44, file: !1, line: 27, type: !11)
+!49 = !DILocalVariable(name: "d", scope: !44, file: !1, line: 28, type: !11)
+!50 = !DILocation(line: 25, column: 11, scope: !44)
+!51 = !DILocation(line: 25, column: 7, scope: !44)
+!52 = !DILocation(line: 26, column: 11, scope: !44)
+!53 = !DILocation(line: 26, column: 7, scope: !44)
+!54 = !DILocation(line: 27, column: 11, scope: !44)
+!55 = !DILocation(line: 27, column: 7, scope: !44)
+!56 = !DILocation(line: 28, column: 11, scope: !44)
+!57 = !DILocation(line: 28, column: 7, scope: !44)
+!58 = !DILocation(line: 29, column: 3, scope: !44)
+!59 = !DILocation(line: 30, column: 3, scope: !44)
+!60 = !DILocation(line: 31, column: 3, scope: !44)
+!61 = distinct !DISubprogram(name: "spill", scope: !1, file: !1, line: 33, type: !9, isLocal: false, isDefinition: true, scopeLine: 33, isOptimized: true, unit: !0, variables: !62)
+!62 = !{!63, !64, !65, !66, !67}
+!63 = !DILocalVariable(name: "a", scope: !61, file: !1, line: 34, type: !11)
+!64 = !DILocalVariable(name: "b", scope: !61, file: !1, line: 35, type: !11)
+!65 = !DILocalVariable(name: "c", scope: !61, file: !1, line: 36, type: !11)
+!66 = !DILocalVariable(name: "d", scope: !61, file: !1, line: 37, type: !11)
+!67 = !DILocalVariable(name: "e", scope: !61, file: !1, line: 38, type: !11)
+!68 = !DILocation(line: 34, column: 11, scope: !61)
+!69 = !DILocation(line: 34, column: 7, scope: !61)
+!70 = !DILocation(line: 35, column: 11, scope: !61)
+!71 = !DILocation(line: 35, column: 7, scope: !61)
+!72 = !DILocation(line: 36, column: 11, scope: !61)
+!73 = !DILocation(line: 36, column: 7, scope: !61)
+!74 = !DILocation(line: 37, column: 11, scope: !61)
+!75 = !DILocation(line: 37, column: 7, scope: !61)
+!76 = !DILocation(line: 38, column: 11, scope: !61)
+!77 = !DILocation(line: 38, column: 7, scope: !61)
+!78 = !DILocation(line: 39, column: 3, scope: !61)
+!79 = !DILocation(line: 40, column: 3, scope: !61)
+!80 = !DILocation(line: 41, column: 3, scope: !61)
diff --git a/llvm/test/DebugInfo/COFF/fpo-realign-alloca.ll b/llvm/test/DebugInfo/COFF/fpo-realign-alloca.ll
new file mode 100644
index 00000000000..7acb501120a
--- /dev/null
+++ b/llvm/test/DebugInfo/COFF/fpo-realign-alloca.ll
@@ -0,0 +1,110 @@
+; RUN: llc < %s | FileCheck %s
+
+; C source:
+; void usethings(double *, void *p);
+; int realign_and_alloca(int n) {
+; double d = 0;
+; void *p = __builtin_alloca(n);
+; usethings(&d, p);
+; return 0;
+; }
+
+; CHECK: _realign_and_alloca: # @realign_and_alloca
+; CHECK: .cv_fpo_proc _realign_and_alloca 4
+; CHECK: pushl %ebp
+; CHECK: .cv_fpo_pushreg %ebp
+; CHECK: movl %esp, %ebp
+; CHECK: .cv_fpo_setframe %ebp
+; CHECK: pushl %esi
+; CHECK: .cv_fpo_pushreg %esi
+; We don't seem to need to describe this AND because at this point CSRs
+; are stored relative to EBP, but it's suspicious.
+; CHECK: andl $-16, %esp
+; CHECK: subl $32, %esp
+; CHECK: .cv_fpo_stackalloc 32
+; CHECK: .cv_fpo_endprologue
+; CHECK: movl %esp, %esi
+; CHECK: leal 8(%esi),
+; CHECK: calll _usethings
+; CHECK: addl $8, %esp
+; CHECK: xorl %eax, %eax
+; CHECK: leal -4(%ebp), %esp
+; CHECK: popl %esi
+; CHECK: popl %ebp
+; CHECK: retl
+; CHECK: .cv_fpo_endproc
+
+
+; ModuleID = 't.c'
+source_filename = "t.c"
+target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+target triple = "i386-pc-windows-msvc19.11.25508"
+
+; Function Attrs: nounwind
+define i32 @realign_and_alloca(i32 %n) local_unnamed_addr #0 !dbg !8 {
+entry:
+ %d = alloca double, align 8
+ tail call void @llvm.dbg.value(metadata i32 %n, metadata !13, metadata !DIExpression()), !dbg !18
+ %0 = bitcast double* %d to i8*, !dbg !19
+ call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %0) #4, !dbg !19
+ tail call void @llvm.dbg.value(metadata double 0.000000e+00, metadata !14, metadata !DIExpression()), !dbg !20
+ store double 0.000000e+00, double* %d, align 8, !dbg !20, !tbaa !21
+ %1 = alloca i8, i32 %n, align 16, !dbg !25
+ tail call void @llvm.dbg.value(metadata i8* %1, metadata !16, metadata !DIExpression()), !dbg !26
+ tail call void @llvm.dbg.value(metadata double* %d, metadata !14, metadata !DIExpression()), !dbg !20
+ call void @usethings(double* nonnull %d, i8* nonnull %1) #4, !dbg !27
+ call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %0) #4, !dbg !28
+ ret i32 0, !dbg !29
+}
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1
+
+declare void @usethings(double*, i8*) local_unnamed_addr #2
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { argmemonly nounwind }
+attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #3 = { nounwind readnone speculatable }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "t.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "cfdc2deff5dc50f95e287f877660d4dd")
+!2 = !{}
+!3 = !{i32 1, !"NumRegisterParameters", i32 0}
+!4 = !{i32 2, !"CodeView", i32 1}
+!5 = !{i32 2, !"Debug Info Version", i32 3}
+!6 = !{i32 1, !"wchar_size", i32 2}
+!7 = !{!"clang version 6.0.0 "}
+!8 = distinct !DISubprogram(name: "realign_and_alloca", scope: !1, file: !1, line: 2, type: !9, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !12)
+!9 = !DISubroutineType(types: !10)
+!10 = !{!11, !11}
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !{!13, !14, !16}
+!13 = !DILocalVariable(name: "n", arg: 1, scope: !8, file: !1, line: 2, type: !11)
+!14 = !DILocalVariable(name: "d", scope: !8, file: !1, line: 3, type: !15)
+!15 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float)
+!16 = !DILocalVariable(name: "p", scope: !8, file: !1, line: 4, type: !17)
+!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 32)
+!18 = !DILocation(line: 2, column: 28, scope: !8)
+!19 = !DILocation(line: 3, column: 3, scope: !8)
+!20 = !DILocation(line: 3, column: 10, scope: !8)
+!21 = !{!22, !22, i64 0}
+!22 = !{!"double", !23, i64 0}
+!23 = !{!"omnipotent char", !24, i64 0}
+!24 = !{!"Simple C/C++ TBAA"}
+!25 = !DILocation(line: 4, column: 13, scope: !8)
+!26 = !DILocation(line: 4, column: 9, scope: !8)
+!27 = !DILocation(line: 5, column: 3, scope: !8)
+!28 = !DILocation(line: 7, column: 1, scope: !8)
+!29 = !DILocation(line: 6, column: 3, scope: !8)
diff --git a/llvm/test/DebugInfo/COFF/fpo-shrink-wrap.ll b/llvm/test/DebugInfo/COFF/fpo-shrink-wrap.ll
new file mode 100644
index 00000000000..3d16a28c106
--- /dev/null
+++ b/llvm/test/DebugInfo/COFF/fpo-shrink-wrap.ll
@@ -0,0 +1,154 @@
+; RUN: llc -enable-shrink-wrap=true < %s | FileCheck %s --check-prefix=ASM
+; RUN: llc -enable-shrink-wrap=true -filetype=obj < %s | llvm-readobj -codeview | FileCheck %s --check-prefix=OBJ
+
+; C source:
+; int doSomething(int*);
+; int __fastcall shrink_wrap_basic(int a, int b, int c, int d) {
+; if (a < b)
+; return a;
+; for (int i = c; i < d; ++i)
+; doSomething(&c);
+; return doSomething(&c);
+; }
+
+; ASM: @shrink_wrap_basic@16: # @"\01@shrink_wrap_basic@16"
+; ASM: .cv_fpo_proc @shrink_wrap_basic@16 8
+; ASM: .cv_loc 0 1 3 9 # t.c:3:9
+; ASM: movl %ecx, %eax
+; ASM: cmpl %edx, %eax
+; ASM: jl [[EPILOGUE:LBB0_[0-9]+]]
+
+; ASM: pushl %ebx
+; ASM: .cv_fpo_pushreg %ebx
+; ASM: pushl %edi
+; ASM: .cv_fpo_pushreg %edi
+; ASM: pushl %esi
+; ASM: .cv_fpo_pushreg %esi
+; ASM: .cv_fpo_endprologue
+
+; ASM: calll _doSomething
+
+; ASM: popl %esi
+; ASM: popl %edi
+; ASM: popl %ebx
+; ASM: [[EPILOGUE]]: # %return
+; ASM: retl $8
+; ASM: Ltmp11:
+; ASM: .cv_fpo_endproc
+
+; Note how RvaStart advances 7 bytes to skip the shrink-wrapped portion.
+; OBJ: SubSectionType: FrameData (0xF5)
+; OBJ: FrameData {
+; OBJ: RvaStart: 0x0
+; OBJ: CodeSize: 0x34
+; OBJ: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+; OBJ: PrologSize: 0x9
+; OBJ: }
+; OBJ: FrameData {
+; OBJ: RvaStart: 0x7
+; OBJ: CodeSize: 0x2D
+; OBJ: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebx $T0 4 - ^ =
+; OBJ: PrologSize: 0x2
+; OBJ: }
+; OBJ: FrameData {
+; OBJ: RvaStart: 0x8
+; OBJ: CodeSize: 0x2C
+; OBJ: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebx $T0 4 - ^ = $edi $T0 8 - ^ =
+; OBJ: PrologSize: 0x1
+; OBJ: }
+; OBJ: FrameData {
+; OBJ: RvaStart: 0x9
+; OBJ: CodeSize: 0x2B
+; OBJ: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebx $T0 4 - ^ = $edi $T0 8 - ^ = $esi $T0 12 - ^ =
+; OBJ: PrologSize: 0x0
+; OBJ: }
+; OBJ-NOT: FrameData
+
+; ModuleID = 't.c'
+source_filename = "t.c"
+target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+target triple = "i386-pc-windows-msvc19.11.25508"
+
+; Function Attrs: nounwind
+define x86_fastcallcc i32 @"\01@shrink_wrap_basic@16"(i32 inreg %a, i32 inreg %b, i32 %c, i32 %d) local_unnamed_addr #0 !dbg !8 {
+entry:
+ %c.addr = alloca i32, align 4
+ tail call void @llvm.dbg.value(metadata i32 %d, metadata !13, metadata !DIExpression()), !dbg !19
+ tail call void @llvm.dbg.value(metadata i32 %c, metadata !14, metadata !DIExpression()), !dbg !20
+ store i32 %c, i32* %c.addr, align 4, !tbaa !21
+ tail call void @llvm.dbg.value(metadata i32 %b, metadata !15, metadata !DIExpression()), !dbg !25
+ tail call void @llvm.dbg.value(metadata i32 %a, metadata !16, metadata !DIExpression()), !dbg !26
+ %cmp = icmp slt i32 %a, %b, !dbg !27
+ br i1 %cmp, label %return, label %for.cond.preheader, !dbg !29
+
+for.cond.preheader: ; preds = %entry
+ br label %for.cond, !dbg !30
+
+for.cond: ; preds = %for.cond.preheader, %for.cond
+ %i.0 = phi i32 [ %inc, %for.cond ], [ %c, %for.cond.preheader ]
+ call void @llvm.dbg.value(metadata i32 %i.0, metadata !17, metadata !DIExpression()), !dbg !32
+ %cmp1 = icmp slt i32 %i.0, %d, !dbg !30
+ call void @llvm.dbg.value(metadata i32* %c.addr, metadata !14, metadata !DIExpression()), !dbg !20
+ %call = call i32 @doSomething(i32* nonnull %c.addr) #3, !dbg !33
+ %inc = add nsw i32 %i.0, 1, !dbg !34
+ call void @llvm.dbg.value(metadata i32 %inc, metadata !17, metadata !DIExpression()), !dbg !32
+ br i1 %cmp1, label %for.cond, label %return, !dbg !35, !llvm.loop !36
+
+return: ; preds = %for.cond, %entry
+ %retval.0 = phi i32 [ %a, %entry ], [ %call, %for.cond ]
+ ret i32 %retval.0, !dbg !38
+}
+
+declare i32 @doSomething(i32*) local_unnamed_addr #1
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone speculatable }
+attributes #3 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "t.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "32f118fd5dd7e65ff7733c49b2f804ef")
+!2 = !{}
+!3 = !{i32 1, !"NumRegisterParameters", i32 0}
+!4 = !{i32 2, !"CodeView", i32 1}
+!5 = !{i32 2, !"Debug Info Version", i32 3}
+!6 = !{i32 1, !"wchar_size", i32 2}
+!7 = !{!"clang version 6.0.0 "}
+!8 = distinct !DISubprogram(name: "shrink_wrap_basic", linkageName: "\01@shrink_wrap_basic@16", scope: !1, file: !1, line: 2, type: !9, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !12)
+!9 = !DISubroutineType(cc: DW_CC_BORLAND_msfastcall, types: !10)
+!10 = !{!11, !11, !11, !11, !11}
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !{!13, !14, !15, !16, !17}
+!13 = !DILocalVariable(name: "d", arg: 4, scope: !8, file: !1, line: 2, type: !11)
+!14 = !DILocalVariable(name: "c", arg: 3, scope: !8, file: !1, line: 2, type: !11)
+!15 = !DILocalVariable(name: "b", arg: 2, scope: !8, file: !1, line: 2, type: !11)
+!16 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 2, type: !11)
+!17 = !DILocalVariable(name: "i", scope: !18, file: !1, line: 5, type: !11)
+!18 = distinct !DILexicalBlock(scope: !8, file: !1, line: 5, column: 3)
+!19 = !DILocation(line: 2, column: 59, scope: !8)
+!20 = !DILocation(line: 2, column: 52, scope: !8)
+!21 = !{!22, !22, i64 0}
+!22 = !{!"int", !23, i64 0}
+!23 = !{!"omnipotent char", !24, i64 0}
+!24 = !{!"Simple C/C++ TBAA"}
+!25 = !DILocation(line: 2, column: 45, scope: !8)
+!26 = !DILocation(line: 2, column: 38, scope: !8)
+!27 = !DILocation(line: 3, column: 9, scope: !28)
+!28 = distinct !DILexicalBlock(scope: !8, file: !1, line: 3, column: 7)
+!29 = !DILocation(line: 3, column: 7, scope: !8)
+!30 = !DILocation(line: 5, column: 21, scope: !31)
+!31 = distinct !DILexicalBlock(scope: !18, file: !1, line: 5, column: 3)
+!32 = !DILocation(line: 5, column: 12, scope: !18)
+!33 = !DILocation(line: 0, scope: !8)
+!34 = !DILocation(line: 5, column: 26, scope: !31)
+!35 = !DILocation(line: 5, column: 3, scope: !18)
+!36 = distinct !{!36, !35, !37}
+!37 = !DILocation(line: 6, column: 19, scope: !18)
+!38 = !DILocation(line: 8, column: 1, scope: !8)
diff --git a/llvm/test/DebugInfo/COFF/fpo-stack-protect.ll b/llvm/test/DebugInfo/COFF/fpo-stack-protect.ll
new file mode 100644
index 00000000000..24d99c51308
--- /dev/null
+++ b/llvm/test/DebugInfo/COFF/fpo-stack-protect.ll
@@ -0,0 +1,114 @@
+; RUN: llc < %s | FileCheck %s
+
+; C source:
+; void escape(int *);
+; int ssp(int a) {
+; int arr[4] = {a, a, a, a};
+; escape(&arr[0]);
+; return a;
+; }
+
+; CHECK: _ssp: # @ssp
+; CHECK: .cv_fpo_proc _ssp 4
+; CHECK: pushl %esi
+; CHECK: .cv_fpo_pushreg %esi
+; CHECK: subl $20, %esp
+; CHECK: .cv_fpo_stackalloc 20
+; CHECK: .cv_fpo_endprologue
+; CHECK: ___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@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)
diff --git a/llvm/test/DebugInfo/COFF/multifunction.ll b/llvm/test/DebugInfo/COFF/multifunction.ll
index 87db2a20eaa..4d14a61ceb3 100644
--- a/llvm/test/DebugInfo/COFF/multifunction.ll
+++ b/llvm/test/DebugInfo/COFF/multifunction.ll
@@ -61,6 +61,7 @@
; X86-NEXT: .short [[C1_END:.*]]-[[C1_START:.*]] #
; X86: [[COMPILE_END]]:
; X86-NEXT: .p2align 2
+; X86-NEXT: .cv_fpo_data _x
; Symbol subsection for x
; X86-NEXT: .long 241
; X86-NEXT: .long [[F1_END:.*]]-[[F1_START:.*]] #
@@ -87,6 +88,7 @@
; Line table subsection for x
; X86: .cv_linetable 0, _x, [[END_OF_X]]
; Symbol subsection for y
+; X86-NEXT: .cv_fpo_data _y
; X86-NEXT: .long 241
; X86-NEXT: .long [[COMPILE_END:.*]]-[[COMPILE_START:.*]] #
; X86-NEXT: [[COMPILE_START]]:
@@ -112,6 +114,7 @@
; Line table subsection for y
; X86: .cv_linetable 1, _y, [[END_OF_Y]]
; Symbol subsection for f
+; X86-NEXT: .cv_fpo_data _f
; X86-NEXT: .long 241
; X86-NEXT: .long [[COMPILE_END:.*]]-[[COMPILE_START:.*]] #
; X86-NEXT: [[COMPILE_START]]:
@@ -145,6 +148,13 @@
; OBJ32: ]
; OBJ32: Subsection [
; OBJ32-NEXT: SubSectionType: Symbols (0xF1)
+; OBJ32: Compile3Sym
+; OBJ32: ]
+; OBJ32: Subsection [
+; OBJ32-NEXT: SubSectionType: FrameData (0xF5)
+; OBJ32: ]
+; OBJ32: Subsection [
+; OBJ32-NEXT: SubSectionType: Symbols (0xF1)
; OBJ32: {{.*}}Proc{{.*}}Sym {
; OBJ32: Kind: S_LPROC32_ID (0x1146)
; OBJ32: CodeSize: 0x6
@@ -158,6 +168,9 @@
; OBJ32-NEXT: SubSectionType: Lines (0xF2)
; OBJ32: ]
; OBJ32: Subsection [
+; OBJ32-NEXT: SubSectionType: FrameData (0xF5)
+; OBJ32: ]
+; OBJ32: Subsection [
; OBJ32-NEXT: SubSectionType: Symbols (0xF1)
; OBJ32: {{.*}}Proc{{.*}}Sym {
; OBJ32: Kind: S_GPROC32_ID (0x1147)
@@ -172,6 +185,9 @@
; OBJ32-NEXT: SubSectionType: Lines (0xF2)
; OBJ32: ]
; OBJ32: Subsection [
+; OBJ32-NEXT: SubSectionType: FrameData (0xF5)
+; OBJ32: ]
+; OBJ32: Subsection [
; OBJ32-NEXT: SubSectionType: Symbols (0xF1)
; OBJ32: {{.*}}Proc{{.*}}Sym {
; OBJ32: Kind: S_GPROC32_ID (0x1147)
diff --git a/llvm/test/DebugInfo/COFF/simple.ll b/llvm/test/DebugInfo/COFF/simple.ll
index 71733d1844b..90a973b4c3f 100644
--- a/llvm/test/DebugInfo/COFF/simple.ll
+++ b/llvm/test/DebugInfo/COFF/simple.ll
@@ -36,6 +36,7 @@
; X86: [[C1_END]]:
; X86-NEXT: [[COMPILE_END]]:
; X86-NEXT: .p2align 2
+; X86-NEXT: .cv_fpo_data _f
; X86-NEXT: .long 241 # Symbol subsection for f
; X86-NEXT: .long [[F1_END:.*]]-[[F1_START:.*]] # Subsection size
; X86-NEXT: [[F1_START]]:
@@ -70,13 +71,21 @@
; OBJ32: Characteristics [ (0x42300040)
; OBJ32: ]
; OBJ32: Relocations [
-; OBJ32-NEXT: 0x64 IMAGE_REL_I386_SECREL _f
-; OBJ32-NEXT: 0x68 IMAGE_REL_I386_SECTION _f
-; OBJ32-NEXT: 0x7C IMAGE_REL_I386_SECREL _f
-; OBJ32-NEXT: 0x80 IMAGE_REL_I386_SECTION _f
+; OBJ32-NEXT: 0x44 IMAGE_REL_I386_DIR32NB _f
+; OBJ32-NEXT: 0x90 IMAGE_REL_I386_SECREL _f
+; OBJ32-NEXT: 0x94 IMAGE_REL_I386_SECTION _f
+; OBJ32-NEXT: 0xA8 IMAGE_REL_I386_SECREL _f
+; OBJ32-NEXT: 0xAC IMAGE_REL_I386_SECTION _f
; OBJ32-NEXT: ]
; OBJ32: Subsection [
; OBJ32-NEXT: SubSectionType: Symbols (0xF1)
+; OBJ32: Compile3Sym
+; OBJ32: ]
+; OBJ32: Subsection [
+; OBJ32-NEXT: SubSectionType: FrameData (0xF5)
+; OBJ32: ]
+; OBJ32: Subsection [
+; OBJ32-NEXT: SubSectionType: Symbols (0xF1)
; OBJ32: {{.*}}Proc{{.*}}Sym {
; OBJ32: CodeSize: 0x6
; OBJ32: DisplayName: f
diff --git a/llvm/test/MC/COFF/cv-fpo-csrs.s b/llvm/test/MC/COFF/cv-fpo-csrs.s
new file mode 100644
index 00000000000..fef7e786078
--- /dev/null
+++ b/llvm/test/MC/COFF/cv-fpo-csrs.s
@@ -0,0 +1,141 @@
+# RUN: llvm-mc -filetype=asm < %s -triple i686-windows-msvc | FileCheck %s --check-prefix=ASM
+# RUN: llvm-mc -filetype=obj < %s -triple i686-windows-msvc | llvm-readobj -codeview | FileCheck %s --check-prefix=OBJ
+
+.globl _foo
+_foo:
+ .cv_fpo_proc _foo 4
+ pushl %ebp
+ .cv_fpo_pushreg ebp # Test without %
+ pushl %ebx
+ .cv_fpo_pushreg %ebx
+ pushl %edi
+ .cv_fpo_pushreg %edi
+ pushl %esi
+ .cv_fpo_pushreg esi
+ subl $20, %esp
+ .cv_fpo_stackalloc 20
+ .cv_fpo_endprologue
+
+ # ASM: .cv_fpo_proc _foo 4
+ # ASM: pushl %ebp
+ # ASM: .cv_fpo_pushreg %ebp
+ # ASM: pushl %ebx
+ # ASM: .cv_fpo_pushreg %ebx
+ # ASM: pushl %edi
+ # ASM: .cv_fpo_pushreg %edi
+ # ASM: pushl %esi
+ # ASM: .cv_fpo_pushreg %esi
+ # ASM: subl $20, %esp
+ # ASM: .cv_fpo_stackalloc 20
+ # ASM: .cv_fpo_endprologue
+
+ # Clobbers
+ xorl %ebp, %ebp
+ xorl %ebx, %ebx
+ xorl %edi, %edi
+ xorl %esi, %esi
+ # Use that stack memory
+ leal 4(%esp), %eax
+ movl %eax, (%esp)
+ calll _bar
+
+ # ASM: calll _bar
+
+ # Epilogue
+ # FIXME: Get FPO data for this once we get it for DWARF.
+ addl $20, %esp
+ popl %esi
+ popl %edi
+ popl %ebx
+ popl %ebp
+ retl
+ .cv_fpo_endproc
+
+ # ASM: .cv_fpo_endproc
+
+ .section .debug$S,"dr"
+ .p2align 2
+ .long 4 # Debug section magic
+ .cv_fpo_data _foo
+ .cv_stringtable
+
+ # ASM: .cv_fpo_data
+
+# OBJ: Subsection [
+# OBJ-NEXT: SubSectionType: FrameData (0xF5)
+# OBJ-NEXT: SubSectionSize: 0xC4
+# OBJ-NEXT: LinkageName: _foo
+# OBJ-NEXT: FrameData {
+# OBJ-NEXT: RvaStart: 0x0
+# OBJ-NEXT: CodeSize: 0x23
+# OBJ-NEXT: LocalSize: 0x0
+# OBJ-NEXT: ParamsSize: 0x4
+# OBJ-NEXT: MaxStackSize: 0x0
+# OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+# OBJ-NEXT: PrologSize: 0x7
+# OBJ-NEXT: SavedRegsSize: 0x0
+# OBJ-NEXT: Flags [ (0x4)
+# OBJ-NEXT: IsFunctionStart (0x4)
+# OBJ-NEXT: ]
+# OBJ-NEXT: }
+# OBJ-NEXT: FrameData {
+# OBJ-NEXT: RvaStart: 0x1
+# OBJ-NEXT: CodeSize: 0x22
+# OBJ-NEXT: LocalSize: 0x0
+# OBJ-NEXT: ParamsSize: 0x4
+# OBJ-NEXT: MaxStackSize: 0x0
+# OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
+# OBJ-NEXT: PrologSize: 0x6
+# OBJ-NEXT: SavedRegsSize: 0x4
+# OBJ-NEXT: Flags [ (0x0)
+# OBJ-NEXT: ]
+# OBJ-NEXT: }
+# OBJ-NEXT: FrameData {
+# OBJ-NEXT: RvaStart: 0x2
+# OBJ-NEXT: CodeSize: 0x21
+# OBJ-NEXT: LocalSize: 0x0
+# OBJ-NEXT: ParamsSize: 0x4
+# OBJ-NEXT: MaxStackSize: 0x0
+# OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ =
+# OBJ-NEXT: PrologSize: 0x5
+# OBJ-NEXT: SavedRegsSize: 0x8
+# OBJ-NEXT: Flags [ (0x0)
+# OBJ-NEXT: ]
+# OBJ-NEXT: }
+# OBJ-NEXT: FrameData {
+# OBJ-NEXT: RvaStart: 0x3
+# OBJ-NEXT: CodeSize: 0x20
+# OBJ-NEXT: LocalSize: 0x0
+# OBJ-NEXT: ParamsSize: 0x4
+# OBJ-NEXT: MaxStackSize: 0x0
+# OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ =
+# OBJ-NEXT: PrologSize: 0x4
+# OBJ-NEXT: SavedRegsSize: 0xC
+# OBJ-NEXT: Flags [ (0x0)
+# OBJ-NEXT: ]
+# OBJ-NEXT: }
+# OBJ-NEXT: FrameData {
+# OBJ-NEXT: RvaStart: 0x4
+# OBJ-NEXT: CodeSize: 0x1F
+# OBJ-NEXT: LocalSize: 0x0
+# OBJ-NEXT: ParamsSize: 0x4
+# OBJ-NEXT: MaxStackSize: 0x0
+# OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ = $esi $T0 16 - ^ =
+# OBJ-NEXT: PrologSize: 0x3
+# OBJ-NEXT: SavedRegsSize: 0x10
+# OBJ-NEXT: Flags [ (0x0)
+# OBJ-NEXT: ]
+# OBJ-NEXT: }
+# OBJ-NEXT: FrameData {
+# OBJ-NEXT: RvaStart: 0x7
+# OBJ-NEXT: CodeSize: 0x1C
+# OBJ-NEXT: LocalSize: 0x14
+# OBJ-NEXT: ParamsSize: 0x4
+# OBJ-NEXT: MaxStackSize: 0x0
+# OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ = $esi $T0 16 - ^ =
+# OBJ-NEXT: PrologSize: 0x0
+# OBJ-NEXT: SavedRegsSize: 0x10
+# OBJ-NEXT: Flags [ (0x0)
+# OBJ-NEXT: ]
+# OBJ-NEXT: }
+# OBJ-NOT: FrameData
diff --git a/llvm/test/MC/COFF/cv-fpo-errors.s b/llvm/test/MC/COFF/cv-fpo-errors.s
new file mode 100644
index 00000000000..baa2fa0d937
--- /dev/null
+++ b/llvm/test/MC/COFF/cv-fpo-errors.s
@@ -0,0 +1,47 @@
+# RUN: not llvm-mc < %s -triple i686-windows-msvc -o /dev/null 2>&1 | FileCheck %s --implicit-check-not=error:
+
+.globl _foo
+_foo:
+ .cv_fpo_proc
+ # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected symbol name
+ .cv_fpo_proc 1
+ # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected symbol name
+ .cv_fpo_proc _foo extra
+ # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected parameter byte count
+ .cv_fpo_proc _foo 4 extra
+ # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: unexpected tokens in '.cv_fpo_proc' directive
+ .cv_fpo_proc _foo 4
+
+ pushl %ebp
+ .cv_fpo_pushreg 1
+ # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: invalid register name in '.cv_fpo_pushreg' directive
+ .cv_fpo_pushreg ebp
+
+ subl $20, %esp
+ .cv_fpo_stackalloc asdf
+ # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected offset in '.cv_fpo_stackalloc' directive
+ .cv_fpo_stackalloc 20 asdf
+ # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: unexpected tokens in '.cv_fpo_stackalloc' directive
+ .cv_fpo_stackalloc 20
+ .cv_fpo_endprologue asdf
+ # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: unexpected tokens in '.cv_fpo_endprologue' directive
+ .cv_fpo_endprologue
+
+ addl $20, %esp
+ popl %ebp
+ retl
+ .cv_fpo_endproc asdf
+ # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: unexpected tokens in '.cv_fpo_endproc' directive
+ .cv_fpo_endproc
+
+ .section .debug$S,"dr"
+ .p2align 2
+ .long 4 # Debug section magic
+ .cv_fpo_data
+ # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected symbol name
+ .cv_fpo_data 1
+ # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: expected symbol name
+ .cv_fpo_data _foo asdf
+ # CHECK: :[[@LINE-1]]:{{[0-9]+}}: error: unexpected tokens in '.cv_fpo_data' directive
+ .cv_fpo_data _foo
+ .long 0
diff --git a/llvm/test/MC/COFF/cv-fpo-setframe.s b/llvm/test/MC/COFF/cv-fpo-setframe.s
new file mode 100644
index 00000000000..12369c7523c
--- /dev/null
+++ b/llvm/test/MC/COFF/cv-fpo-setframe.s
@@ -0,0 +1,144 @@
+# RUN: llvm-mc -filetype=asm < %s -triple i686-windows-msvc | FileCheck %s --check-prefix=ASM
+# RUN: llvm-mc -filetype=obj < %s -triple i686-windows-msvc | llvm-readobj -codeview | FileCheck %s --check-prefix=OBJ
+
+.globl _foo
+_foo:
+ .cv_fpo_proc _foo 4
+ pushl %ebp
+ .cv_fpo_pushreg %ebp
+ movl %ebp, %esp
+ .cv_fpo_setframe %ebp
+ pushl %ebx
+ .cv_fpo_pushreg %ebx
+ pushl %edi
+ .cv_fpo_pushreg %edi
+ pushl %esi
+ .cv_fpo_pushreg esi
+ subl $20, %esp
+ .cv_fpo_stackalloc 20
+ .cv_fpo_endprologue
+
+ # ASM: .cv_fpo_proc _foo 4
+ # ASM: pushl %ebp
+ # ASM: .cv_fpo_pushreg %ebp
+ # ASM: movl %ebp, %esp
+ # ASM: .cv_fpo_setframe %ebp
+ # ASM: pushl %ebx
+ # ASM: .cv_fpo_pushreg %ebx
+ # ASM: pushl %edi
+ # ASM: .cv_fpo_pushreg %edi
+ # ASM: pushl %esi
+ # ASM: .cv_fpo_pushreg %esi
+ # ASM: subl $20, %esp
+ # ASM: .cv_fpo_stackalloc 20
+ # ASM: .cv_fpo_endprologue
+
+ # Clobbers
+ xorl %ebx, %ebx
+ xorl %edi, %edi
+ xorl %esi, %esi
+ # Use that stack memory
+ leal 4(%esp), %eax
+ movl %eax, (%esp)
+ calll _bar
+
+ # ASM: calll _bar
+
+ # Epilogue
+ # FIXME: Get FPO data for this once we get it for DWARF.
+ addl $20, %esp
+ popl %esi
+ popl %edi
+ popl %ebx
+ popl %ebp
+ retl
+ .cv_fpo_endproc
+
+ # ASM: .cv_fpo_endproc
+
+ .section .debug$S,"dr"
+ .p2align 2
+ .long 4 # Debug section magic
+ .cv_fpo_data _foo
+ .cv_stringtable
+
+ # ASM: .cv_fpo_data
+
+# OBJ: Subsection [
+# OBJ-NEXT: SubSectionType: FrameData (0xF5)
+# OBJ-NEXT: SubSectionSize:
+# OBJ-NEXT: LinkageName: _foo
+# OBJ-NEXT: FrameData {
+# OBJ-NEXT: RvaStart: 0x0
+# OBJ-NEXT: CodeSize: 0x23
+# OBJ-NEXT: LocalSize: 0x0
+# OBJ-NEXT: ParamsSize: 0x4
+# OBJ-NEXT: MaxStackSize: 0x0
+# OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+# OBJ-NEXT: PrologSize: 0x9
+# OBJ-NEXT: SavedRegsSize: 0x0
+# OBJ-NEXT: Flags [ (0x4)
+# OBJ-NEXT: IsFunctionStart (0x4)
+# OBJ-NEXT: ]
+# OBJ-NEXT: }
+# OBJ-NEXT: FrameData {
+# OBJ-NEXT: RvaStart: 0x1
+# OBJ-NEXT: CodeSize: 0x22
+# OBJ-NEXT: LocalSize: 0x0
+# OBJ-NEXT: ParamsSize: 0x4
+# OBJ-NEXT: MaxStackSize: 0x0
+# OBJ-NEXT: FrameFunc: $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
+# OBJ-NEXT: PrologSize: 0x8
+# OBJ-NEXT: SavedRegsSize: 0x4
+# OBJ-NEXT: Flags [ (0x0)
+# OBJ-NEXT: ]
+# OBJ-NEXT: }
+# OBJ-NEXT: FrameData {
+# OBJ-NEXT: RvaStart: 0x3
+# OBJ-NEXT: CodeSize: 0x20
+# OBJ-NEXT: LocalSize: 0x0
+# OBJ-NEXT: ParamsSize: 0x4
+# OBJ-NEXT: MaxStackSize: 0x0
+# OBJ-NEXT: FrameFunc: $T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
+# OBJ-NEXT: PrologSize: 0x6
+# OBJ-NEXT: SavedRegsSize: 0x4
+# OBJ-NEXT: Flags [ (0x0)
+# OBJ-NEXT: ]
+# OBJ-NEXT: }
+# OBJ-NEXT: FrameData {
+# OBJ-NEXT: RvaStart: 0x4
+# OBJ-NEXT: CodeSize: 0x1F
+# OBJ-NEXT: LocalSize: 0x0
+# OBJ-NEXT: ParamsSize: 0x4
+# OBJ-NEXT: MaxStackSize: 0x0
+# OBJ-NEXT: FrameFunc: $T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ =
+# OBJ-NEXT: PrologSize: 0x5
+# OBJ-NEXT: SavedRegsSize: 0x8
+# OBJ-NEXT: Flags [ (0x0)
+# OBJ-NEXT: ]
+# OBJ-NEXT: }
+# OBJ-NEXT: FrameData {
+# OBJ-NEXT: RvaStart: 0x5
+# OBJ-NEXT: CodeSize: 0x1E
+# OBJ-NEXT: LocalSize: 0x0
+# OBJ-NEXT: ParamsSize: 0x4
+# OBJ-NEXT: MaxStackSize: 0x0
+# OBJ-NEXT: FrameFunc: $T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ =
+# OBJ-NEXT: PrologSize: 0x4
+# OBJ-NEXT: SavedRegsSize: 0xC
+# OBJ-NEXT: Flags [ (0x0)
+# OBJ-NEXT: ]
+# OBJ-NEXT: }
+# OBJ-NEXT: FrameData {
+# OBJ-NEXT: RvaStart: 0x6
+# OBJ-NEXT: CodeSize: 0x1D
+# OBJ-NEXT: LocalSize: 0x0
+# OBJ-NEXT: ParamsSize: 0x4
+# OBJ-NEXT: MaxStackSize: 0x0
+# OBJ-NEXT: FrameFunc: $T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $ebx $T0 8 - ^ = $edi $T0 12 - ^ = $esi $T0 16 - ^ =
+# OBJ-NEXT: PrologSize: 0x3
+# OBJ-NEXT: SavedRegsSize: 0x10
+# OBJ-NEXT: Flags [ (0x0)
+# OBJ-NEXT: ]
+# OBJ-NEXT: }
+# OBJ-NOT: FrameData
OpenPOWER on IntegriCloud