Deduplicate S_CONSTANTs in LLD.

Summary: Deduplicate S_CONSTANTS when linking, if they have the same value.

Reviewers: rnk

Subscribers: hiraditya, llvm-commits

Tags: #llvm

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

git-svn-id: https://llvm.org/svn/llvm-project/lld/trunk@363089 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/COFF/Inputs/pdb-global-constants-a.s b/test/COFF/Inputs/pdb-global-constants-a.s
new file mode 100644
index 0000000..7b1d34c
--- /dev/null
+++ b/test/COFF/Inputs/pdb-global-constants-a.s
@@ -0,0 +1,214 @@
+	.text
+	.def	 @feat.00;
+	.scl	3;
+	.type	0;
+	.endef
+	.globl	@feat.00
+.set @feat.00, 0
+	.file	"t.cpp"
+	.def	 main;
+	.scl	2;
+	.type	32;
+	.endef
+	.globl	main                    # -- Begin function main
+	.p2align	4, 0x90
+main:                                   # @main
+.Lfunc_begin0:
+	.cv_func_id 0
+	.cv_file	1 "C:\\src\\testing\\t.cpp" "D28AB0CC784E17E5DF9BBB49CB629C81" 1
+	.cv_loc	0 1 4 0                 # t.cpp:4:0
+.seh_proc main
+# %bb.0:                                # %entry
+	pushq	%rax
+	.seh_stackalloc 8
+	.seh_endprologue
+	movl	$0, 4(%rsp)
+.Ltmp0:
+	movl	$83, %eax
+	popq	%rcx
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.seh_handlerdata
+	.text
+	.seh_endproc
+                                        # -- End function
+	.section	.debug$S,"dr"
+	.p2align	2
+	.long	4                       # Debug section magic
+	.long	241
+	.long	.Ltmp3-.Ltmp2           # Subsection size
+.Ltmp2:
+	.short	.Ltmp5-.Ltmp4           # Record length
+.Ltmp4:
+	.short	4412                    # Record kind: S_COMPILE3
+	.long	1                       # Flags and language
+	.short	208                     # CPUType
+	.short	9                       # Frontend version
+	.short	0
+	.short	0
+	.short	0
+	.short	9000                    # Backend version
+	.short	0
+	.short	0
+	.short	0
+	.asciz	"clang version 9.0.0 (https://github.com/llvm/llvm-project.git ad522e17b285b1f2667163d52da5abf0968ec650)" # Null-terminated compiler version string
+	.p2align	2
+.Ltmp5:
+.Ltmp3:
+	.p2align	2
+	.long	241                     # Symbol subsection for main
+	.long	.Ltmp7-.Ltmp6           # Subsection size
+.Ltmp6:
+	.short	.Ltmp9-.Ltmp8           # Record length
+.Ltmp8:
+	.short	4423                    # Record kind: S_GPROC32_ID
+	.long	0                       # PtrParent
+	.long	0                       # PtrEnd
+	.long	0                       # PtrNext
+	.long	.Lfunc_end0-main        # Code size
+	.long	0                       # Offset after prologue
+	.long	0                       # Offset before epilogue
+	.long	4098                    # Function type index
+	.secrel32	main            # Function section relative address
+	.secidx	main                    # Function section index
+	.byte	0                       # Flags
+	.asciz	"main"                  # Function name
+	.p2align	2
+.Ltmp9:
+	.short	.Ltmp11-.Ltmp10         # Record length
+.Ltmp10:
+	.short	4114                    # Record kind: S_FRAMEPROC
+	.long	8                       # FrameSize
+	.long	0                       # Padding
+	.long	0                       # Offset of padding
+	.long	0                       # Bytes of callee saved registers
+	.long	0                       # Exception handler offset
+	.short	0                       # Exception handler section
+	.long	81920                   # Flags (defines frame register)
+	.p2align	2
+.Ltmp11:
+	.short	2                       # Record length
+	.short	4431                    # Record kind: S_PROC_ID_END
+.Ltmp7:
+	.p2align	2
+	.cv_linetable	0, main, .Lfunc_end0
+	.long	241                     # Symbol subsection for globals
+	.long	.Ltmp13-.Ltmp12         # Subsection size
+.Ltmp12:
+	.short	.Ltmp15-.Ltmp14         # Record length
+.Ltmp14:
+	.short	4359                    # Record kind: S_CONSTANT
+	.long	4099                    # Type
+	.byte	0x29, 0x00              # Value
+	.asciz	"Foo"                   # Name
+	.p2align	2
+.Ltmp15:
+	.short	.Ltmp17-.Ltmp16         # Record length
+.Ltmp16:
+	.short	4359                    # Record kind: S_CONSTANT
+	.long	4099                    # Type
+	.byte	0x2a, 0x00              # Value
+	.asciz	"Bar"                   # Name
+	.p2align	2
+.Ltmp17:
+.Ltmp13:
+	.p2align	2
+	.cv_filechecksums               # File index to string table offset subsection
+	.cv_stringtable                 # String table
+	.long	241
+	.long	.Ltmp19-.Ltmp18         # Subsection size
+.Ltmp18:
+	.short	.Ltmp21-.Ltmp20         # Record length
+.Ltmp20:
+	.short	4428                    # Record kind: S_BUILDINFO
+	.long	4102                    # LF_BUILDINFO index
+	.p2align	2
+.Ltmp21:
+.Ltmp19:
+	.p2align	2
+	.section	.debug$T,"dr"
+	.p2align	2
+	.long	4                       # Debug section magic
+	# ArgList (0x1000) {
+	#   TypeLeafKind: LF_ARGLIST (0x1201)
+	#   NumArgs: 0
+	#   Arguments [
+	#   ]
+	# }
+	.byte	0x06, 0x00, 0x01, 0x12
+	.byte	0x00, 0x00, 0x00, 0x00
+	# Procedure (0x1001) {
+	#   TypeLeafKind: LF_PROCEDURE (0x1008)
+	#   ReturnType: int (0x74)
+	#   CallingConvention: NearC (0x0)
+	#   FunctionOptions [ (0x0)
+	#   ]
+	#   NumParameters: 0
+	#   ArgListType: () (0x1000)
+	# }
+	.byte	0x0e, 0x00, 0x08, 0x10
+	.byte	0x74, 0x00, 0x00, 0x00
+	.byte	0x00, 0x00, 0x00, 0x00
+	.byte	0x00, 0x10, 0x00, 0x00
+	# FuncId (0x1002) {
+	#   TypeLeafKind: LF_FUNC_ID (0x1601)
+	#   ParentScope: 0x0
+	#   FunctionType: int () (0x1001)
+	#   Name: main
+	# }
+	.byte	0x12, 0x00, 0x01, 0x16
+	.byte	0x00, 0x00, 0x00, 0x00
+	.byte	0x01, 0x10, 0x00, 0x00
+	.byte	0x6d, 0x61, 0x69, 0x6e
+	.byte	0x00, 0xf3, 0xf2, 0xf1
+	# Modifier (0x1003) {
+	#   TypeLeafKind: LF_MODIFIER (0x1001)
+	#   ModifiedType: int (0x74)
+	#   Modifiers [ (0x1)
+	#     Const (0x1)
+	#   ]
+	# }
+	.byte	0x0a, 0x00, 0x01, 0x10
+	.byte	0x74, 0x00, 0x00, 0x00
+	.byte	0x01, 0x00, 0xf2, 0xf1
+	# StringId (0x1004) {
+	#   TypeLeafKind: LF_STRING_ID (0x1605)
+	#   Id: 0x0
+	#   StringData: C:\src\testing
+	# }
+	.byte	0x16, 0x00, 0x05, 0x16
+	.byte	0x00, 0x00, 0x00, 0x00
+	.byte	0x43, 0x3a, 0x5c, 0x73
+	.byte	0x72, 0x63, 0x5c, 0x74
+	.byte	0x65, 0x73, 0x74, 0x69
+	.byte	0x6e, 0x67, 0x00, 0xf1
+	# StringId (0x1005) {
+	#   TypeLeafKind: LF_STRING_ID (0x1605)
+	#   Id: 0x0
+	#   StringData: t.cpp
+	# }
+	.byte	0x0e, 0x00, 0x05, 0x16
+	.byte	0x00, 0x00, 0x00, 0x00
+	.byte	0x74, 0x2e, 0x63, 0x70
+	.byte	0x70, 0x00, 0xf2, 0xf1
+	# BuildInfo (0x1006) {
+	#   TypeLeafKind: LF_BUILDINFO (0x1603)
+	#   NumArgs: 5
+	#   Arguments [
+	#     ArgType: C:\src\testing (0x1004)
+	#     ArgType: 0x0
+	#     ArgType: t.cpp (0x1005)
+	#     ArgType: 0x0
+	#     ArgType: 0x0
+	#   ]
+	# }
+	.byte	0x1a, 0x00, 0x03, 0x16
+	.byte	0x05, 0x00, 0x04, 0x10
+	.byte	0x00, 0x00, 0x00, 0x00
+	.byte	0x00, 0x00, 0x05, 0x10
+	.byte	0x00, 0x00, 0x00, 0x00
+	.byte	0x00, 0x00, 0x00, 0x00
+	.byte	0x00, 0x00, 0xf2, 0xf1
+
+	.addrsig
diff --git a/test/COFF/Inputs/pdb-global-constants-b.s b/test/COFF/Inputs/pdb-global-constants-b.s
new file mode 100644
index 0000000..1d987a5
--- /dev/null
+++ b/test/COFF/Inputs/pdb-global-constants-b.s
@@ -0,0 +1,204 @@
+	.text
+	.def	 @feat.00;
+	.scl	3;
+	.type	0;
+	.endef
+	.globl	@feat.00
+.set @feat.00, 0
+	.file	"t2.cpp"
+	.def	 "?foobar@@YAHXZ";
+	.scl	2;
+	.type	32;
+	.endef
+	.globl	"?foobar@@YAHXZ"        # -- Begin function ?foobar@@YAHXZ
+	.p2align	4, 0x90
+"?foobar@@YAHXZ":                       # @"?foobar@@YAHXZ"
+.Lfunc_begin0:
+	.cv_func_id 0
+# %bb.0:                                # %entry
+	.cv_file	1 "C:\\src\\testing\\t2.cpp" "C9D7AF07363FDE8EC16D73EC30039C5B" 1
+	.cv_loc	0 1 5 0                 # t2.cpp:5:0
+	movl	$84, %eax
+	retq
+.Ltmp0:
+.Lfunc_end0:
+                                        # -- End function
+	.section	.debug$S,"dr"
+	.p2align	2
+	.long	4                       # Debug section magic
+	.long	241
+	.long	.Ltmp2-.Ltmp1           # Subsection size
+.Ltmp1:
+	.short	.Ltmp4-.Ltmp3           # Record length
+.Ltmp3:
+	.short	4412                    # Record kind: S_COMPILE3
+	.long	1                       # Flags and language
+	.short	208                     # CPUType
+	.short	9                       # Frontend version
+	.short	0
+	.short	0
+	.short	0
+	.short	9000                    # Backend version
+	.short	0
+	.short	0
+	.short	0
+	.asciz	"clang version 9.0.0 (https://github.com/llvm/llvm-project.git ad522e17b285b1f2667163d52da5abf0968ec650)" # Null-terminated compiler version string
+	.p2align	2
+.Ltmp4:
+.Ltmp2:
+	.p2align	2
+	.long	241                     # Symbol subsection for foobar
+	.long	.Ltmp6-.Ltmp5           # Subsection size
+.Ltmp5:
+	.short	.Ltmp8-.Ltmp7           # Record length
+.Ltmp7:
+	.short	4423                    # Record kind: S_GPROC32_ID
+	.long	0                       # PtrParent
+	.long	0                       # PtrEnd
+	.long	0                       # PtrNext
+	.long	.Lfunc_end0-"?foobar@@YAHXZ" # Code size
+	.long	0                       # Offset after prologue
+	.long	0                       # Offset before epilogue
+	.long	4098                    # Function type index
+	.secrel32	"?foobar@@YAHXZ" # Function section relative address
+	.secidx	"?foobar@@YAHXZ"        # Function section index
+	.byte	0                       # Flags
+	.asciz	"foobar"                # Function name
+	.p2align	2
+.Ltmp8:
+	.short	.Ltmp10-.Ltmp9          # Record length
+.Ltmp9:
+	.short	4114                    # Record kind: S_FRAMEPROC
+	.long	0                       # FrameSize
+	.long	0                       # Padding
+	.long	0                       # Offset of padding
+	.long	0                       # Bytes of callee saved registers
+	.long	0                       # Exception handler offset
+	.short	0                       # Exception handler section
+	.long	0                       # Flags (defines frame register)
+	.p2align	2
+.Ltmp10:
+	.short	2                       # Record length
+	.short	4431                    # Record kind: S_PROC_ID_END
+.Ltmp6:
+	.p2align	2
+	.cv_linetable	0, "?foobar@@YAHXZ", .Lfunc_end0
+	.long	241                     # Symbol subsection for globals
+	.long	.Ltmp12-.Ltmp11         # Subsection size
+.Ltmp11:
+	.short	.Ltmp14-.Ltmp13         # Record length
+.Ltmp13:
+	.short	4359                    # Record kind: S_CONSTANT
+	.long	4099                    # Type
+	.byte	0x2a, 0x00              # Value
+	.asciz	"Foo"                   # Name
+	.p2align	2
+.Ltmp14:
+	.short	.Ltmp16-.Ltmp15         # Record length
+.Ltmp15:
+	.short	4359                    # Record kind: S_CONSTANT
+	.long	4099                    # Type
+	.byte	0x2a, 0x00              # Value
+	.asciz	"Bar"                   # Name
+	.p2align	2
+.Ltmp16:
+.Ltmp12:
+	.p2align	2
+	.cv_filechecksums               # File index to string table offset subsection
+	.cv_stringtable                 # String table
+	.long	241
+	.long	.Ltmp18-.Ltmp17         # Subsection size
+.Ltmp17:
+	.short	.Ltmp20-.Ltmp19         # Record length
+.Ltmp19:
+	.short	4428                    # Record kind: S_BUILDINFO
+	.long	4102                    # LF_BUILDINFO index
+	.p2align	2
+.Ltmp20:
+.Ltmp18:
+	.p2align	2
+	.section	.debug$T,"dr"
+	.p2align	2
+	.long	4                       # Debug section magic
+	# ArgList (0x1000) {
+	#   TypeLeafKind: LF_ARGLIST (0x1201)
+	#   NumArgs: 0
+	#   Arguments [
+	#   ]
+	# }
+	.byte	0x06, 0x00, 0x01, 0x12
+	.byte	0x00, 0x00, 0x00, 0x00
+	# Procedure (0x1001) {
+	#   TypeLeafKind: LF_PROCEDURE (0x1008)
+	#   ReturnType: int (0x74)
+	#   CallingConvention: NearC (0x0)
+	#   FunctionOptions [ (0x0)
+	#   ]
+	#   NumParameters: 0
+	#   ArgListType: () (0x1000)
+	# }
+	.byte	0x0e, 0x00, 0x08, 0x10
+	.byte	0x74, 0x00, 0x00, 0x00
+	.byte	0x00, 0x00, 0x00, 0x00
+	.byte	0x00, 0x10, 0x00, 0x00
+	# FuncId (0x1002) {
+	#   TypeLeafKind: LF_FUNC_ID (0x1601)
+	#   ParentScope: 0x0
+	#   FunctionType: int () (0x1001)
+	#   Name: foobar
+	# }
+	.byte	0x12, 0x00, 0x01, 0x16
+	.byte	0x00, 0x00, 0x00, 0x00
+	.byte	0x01, 0x10, 0x00, 0x00
+	.byte	0x66, 0x6f, 0x6f, 0x62
+	.byte	0x61, 0x72, 0x00, 0xf1
+	# Modifier (0x1003) {
+	#   TypeLeafKind: LF_MODIFIER (0x1001)
+	#   ModifiedType: int (0x74)
+	#   Modifiers [ (0x1)
+	#     Const (0x1)
+	#   ]
+	# }
+	.byte	0x0a, 0x00, 0x01, 0x10
+	.byte	0x74, 0x00, 0x00, 0x00
+	.byte	0x01, 0x00, 0xf2, 0xf1
+	# StringId (0x1004) {
+	#   TypeLeafKind: LF_STRING_ID (0x1605)
+	#   Id: 0x0
+	#   StringData: C:\src\testing
+	# }
+	.byte	0x16, 0x00, 0x05, 0x16
+	.byte	0x00, 0x00, 0x00, 0x00
+	.byte	0x43, 0x3a, 0x5c, 0x73
+	.byte	0x72, 0x63, 0x5c, 0x74
+	.byte	0x65, 0x73, 0x74, 0x69
+	.byte	0x6e, 0x67, 0x00, 0xf1
+	# StringId (0x1005) {
+	#   TypeLeafKind: LF_STRING_ID (0x1605)
+	#   Id: 0x0
+	#   StringData: t2.cpp
+	# }
+	.byte	0x0e, 0x00, 0x05, 0x16
+	.byte	0x00, 0x00, 0x00, 0x00
+	.byte	0x74, 0x32, 0x2e, 0x63
+	.byte	0x70, 0x70, 0x00, 0xf1
+	# BuildInfo (0x1006) {
+	#   TypeLeafKind: LF_BUILDINFO (0x1603)
+	#   NumArgs: 5
+	#   Arguments [
+	#     ArgType: C:\src\testing (0x1004)
+	#     ArgType: 0x0
+	#     ArgType: t2.cpp (0x1005)
+	#     ArgType: 0x0
+	#     ArgType: 0x0
+	#   ]
+	# }
+	.byte	0x1a, 0x00, 0x03, 0x16
+	.byte	0x05, 0x00, 0x04, 0x10
+	.byte	0x00, 0x00, 0x00, 0x00
+	.byte	0x00, 0x00, 0x05, 0x10
+	.byte	0x00, 0x00, 0x00, 0x00
+	.byte	0x00, 0x00, 0x00, 0x00
+	.byte	0x00, 0x00, 0xf2, 0xf1
+
+	.addrsig
diff --git a/test/COFF/pdb-global-constants.test b/test/COFF/pdb-global-constants.test
new file mode 100644
index 0000000..b646fc9
--- /dev/null
+++ b/test/COFF/pdb-global-constants.test
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj %S/Inputs/pdb-global-constants-a.s -o %t-a.obj -triple x86_64-windows-msvc
+# RUN: llvm-mc -filetype=obj %S/Inputs/pdb-global-constants-b.s -o %t-b.obj -triple x86_64-windows-msvc
+# RUN: lld-link -entry:main -nodefaultlib %t-a.obj %t-b.obj -out:%t.exe -pdb:%t.pdb -debug
+# RUN: llvm-pdbutil dump -globals %t.pdb | FileCheck %s
+
+# Test that lld deduplicates S_CONSTANT records with the same name and value.
+#
+# Compiled from this C code, using
+# clang t.cpp -g -gcodeview -S
+#
+# %t-a.cpp:
+# const int Foo = 41;
+# const int Bar = 42;
+# int main() { return Foo + Bar; }
+#
+# %t-b.cpp:
+# const int Foo = 42;
+# const int Bar = 42;
+# int foobar() { return Foo + Bar; }
+
+CHECK:                       Global Symbols
+CHECK:           88 | S_CONSTANT [size = 16] `Bar`
+CHECK-NEXT:           type = 0x1002 (const int), value = 42
+CHECK-NEXT:      72 | S_CONSTANT [size = 16] `Foo`
+CHECK-NEXT:           type = 0x1002 (const int), value = 41
+CHECK-NEXT:     128 | S_CONSTANT [size = 16] `Foo`
+CHECK-NEXT:           type = 0x1002 (const int), value = 42