Re: [committed] libstdc++: Add std::is_scoped_enum for C++23

2021-03-20 Thread Jonathan Wakely via Gcc-patches
On Sat, 20 Mar 2021, 01:13 Tim Song via Libstdc++, 
wrote:

> On Fri, Mar 19, 2021 at 3:13 PM Jonathan Wakely via Libstdc++
>  wrote:
> >
> > Implement this C++23 feature, as proposed by P1048R1.
> >
> > This implementation assumes that a C++23 compiler supports concepts
> > already. I don't see any point in using preprocessor hacks to detect
> > compilers which define __cplusplus to a post-C++20 value but don't
> > support concepts yet.
> >
> > libstdc++-v3/ChangeLog:
> >
> > * include/std/type_traits (is_scoped_enum): Define.
> > * include/std/version (__cpp_lib_is_scoped_enum): Define.
> > * testsuite/20_util/is_scoped_enum/value.cc: New test.
> > * testsuite/20_util/is_scoped_enum/version.cc: New test.
> >
> > Tested powerpc64le-linux. Committed to trunk.
> >
>
> Using __underlying_type breaks for incomplete enumeration types. GCC
> doesn't have incomplete scoped enums due to
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89025 but unscoped ones
> exist:
>
> enum E {
> x = std::is_scoped_enum_v
> };
>

Thanks, I'll just use int then. Maybe not until Monday though.


Re: [patch, fortran] Also use size estimate for vector-matrix matmul

2021-03-20 Thread Thomas Koenig via Gcc-patches



Hi Jerry and Steve,


Yes Ok for trunk.


Thanks for the heads-up and the review, committed as r11-7742.

Best regards

Thomas


[PATCH] x86: Check cfun != NULL before accessing silent_p

2021-03-20 Thread H.J. Lu via Gcc-patches
Since construct_container may be called with cfun == NULL, check
cfun != NULL before accessing silent_p.

gcc/

PR target/99679
* config/i386/i386.c (construct_container): Check cfun != NULL
before accessing silent_p.

gcc/testsuite/

PR target/99679
* g++.target/i386/pr99679.C: New test.
---
 gcc/config/i386/i386.c  |   4 +-
 gcc/testsuite/g++.target/i386/pr99679.C | 144 
 2 files changed, 146 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.target/i386/pr99679.C

diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 714349094bd..7c41302c75b 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -2540,7 +2540,7 @@ construct_container (machine_mode mode, machine_mode 
orig_mode,
 {
   /* Return early if we shouldn't raise an error for invalid
 calls.  */
-  if (cfun->machine->silent_p)
+  if (cfun != NULL && cfun->machine->silent_p)
return NULL;
   if (in_return)
{
@@ -2568,7 +2568,7 @@ construct_container (machine_mode mode, machine_mode 
orig_mode,
{
  /* Return early if we shouldn't raise an error for invalid
 calls.  */
- if (cfun->machine->silent_p)
+ if (cfun != NULL && cfun->machine->silent_p)
return NULL;
  if (!issued_x87_ret_error)
{
diff --git a/gcc/testsuite/g++.target/i386/pr99679.C 
b/gcc/testsuite/g++.target/i386/pr99679.C
new file mode 100644
index 000..3570d34cf51
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/pr99679.C
@@ -0,0 +1,144 @@
+// { dg-do compile }
+// { dg-options "-Ofast -fipa-pta -mno-80387" }
+
+#include 
+
+extern "C" void abort (void);
+
+int v1 = 8;
+long int v2 = 3;
+void *v3 = (void *) &v2;
+struct A { char c[16]; } v4 = { "foo" };
+long double v5 = 40;
+char seen[20];
+int cnt;
+
+__attribute__ ((noinline)) int
+foo1 (int x, int y, ...)
+{
+  int i;
+  long int l;
+  void *v;
+  struct A a;
+  long double ld;
+  va_list ap;
+
+  va_start (ap, y);
+  if (x < 0 || x >= 20 || seen[x])
+abort ();
+  seen[x] = ++cnt;
+  if (y != 6)
+abort ();
+  i = va_arg (ap, int);
+  if (i != 5)
+abort ();
+  switch (x)
+{
+case 0:
+  i = va_arg (ap, int);
+  if (i != 9 || v1 != 9)
+   abort ();
+  a = va_arg (ap, struct A);
+  if (__builtin_memcmp (a.c, v4.c, sizeof (a.c)) != 0)
+   abort ();
+  v = (void *) va_arg (ap, struct A *);
+  if (v != (void *) &v4)
+   abort ();
+  l = va_arg (ap, long int);
+  if (l != 3 || v2 != 4)
+   abort ();
+  break;
+case 1:
+  ld = va_arg (ap, long double);
+  if (ld != 41 || v5 != ld)
+   abort ();
+  i = va_arg (ap, int);
+  if (i != 8)
+   abort ();
+  v = va_arg (ap, void *);
+  if (v != &v2)
+   abort ();
+  break;
+case 2:
+  break;
+default:
+  abort ();
+}
+  va_end (ap);
+  return x;
+}
+
+__attribute__ ((noinline)) int
+foo2 (int x, int y, ...)
+{
+  long long int ll;
+  void *v;
+  struct A a, b;
+  long double ld;
+  va_list ap;
+
+  va_start (ap, y);
+  if (x < 0 || x >= 20 || seen[x])
+abort ();
+  seen[x] = ++cnt | 64;
+  if (y != 10)
+abort ();
+  switch (x)
+{
+case 11:
+  break;
+case 12:
+  ld = va_arg (ap, long double);
+  if (ld != 41 || v5 != 40)
+   abort ();
+  a = va_arg (ap, struct A);
+  if (__builtin_memcmp (a.c, v4.c, sizeof (a.c)) != 0)
+   abort ();
+  b = va_arg (ap, struct A);
+  if (__builtin_memcmp (b.c, v4.c, sizeof (b.c)) != 0)
+   abort ();
+  v = va_arg (ap, void *);
+  if (v != &v2)
+   abort ();
+  ll = va_arg (ap, long long int);
+  if (ll != 16LL)
+   abort ();
+  break;
+case 2:
+  break;
+default:
+  abort ();
+}
+  va_end (ap);
+  return x + 8;
+}
+
+__attribute__ ((noinline)) int
+foo3 (void)
+{
+  return 6;
+}
+
+extern inline __attribute__ ((always_inline, gnu_inline)) int
+bar (int x, ...)
+{
+  if (x < 10)
+return foo1 (x, foo3 (), 5, __builtin_va_arg_pack ());
+  return foo2 (x, foo3 () + 4, __builtin_va_arg_pack ());
+}
+
+int
+main (void)
+{
+  if (bar (0, ++v1, v4, &v4, v2++) != 0)
+abort ();
+  if (bar (1, ++v5, 8, v3) != 1)
+abort ();
+  if (bar (2) != 2)
+abort ();
+  if (bar (v1 + 2) != 19)
+abort ();
+  if (bar (v1 + 3, v5--, v4, v4, v3, 16LL) != 20)
+abort ();
+  return 0;
+} // { dg-error "x87 register return with x87 disabled" "" { target { ! ia32 } 
} }
-- 
2.30.2



Re: [PATCH] x86: Check cfun != NULL before accessing silent_p

2021-03-20 Thread Martin Liška

On 3/20/21 1:21 PM, H.J. Lu wrote:

|Since construct_container may be called with cfun == NULL, check cfun != NULL 
before accessing silent_p. |


Thank you for the quick fix.

Please use the minimal reproducer for a test-case:

$ cat va-arg-pack-1.C
#include 
void abort() {
  double ld;
  va_list ap;
  ld = va_arg(ap, long double);
  if (ld)
abort();
}

Martin


Re: [committed] libstdc++: Add std::is_scoped_enum for C++23

2021-03-20 Thread Tim Song via Gcc-patches
On Sat, Mar 20, 2021 at 3:58 AM Jonathan Wakely  wrote:
>
>
>
> On Sat, 20 Mar 2021, 01:13 Tim Song via Libstdc++,  
> wrote:
>>
>> On Fri, Mar 19, 2021 at 3:13 PM Jonathan Wakely via Libstdc++
>>  wrote:
>> >
>> > Implement this C++23 feature, as proposed by P1048R1.
>> >
>> > This implementation assumes that a C++23 compiler supports concepts
>> > already. I don't see any point in using preprocessor hacks to detect
>> > compilers which define __cplusplus to a post-C++20 value but don't
>> > support concepts yet.
>> >
>> > libstdc++-v3/ChangeLog:
>> >
>> > * include/std/type_traits (is_scoped_enum): Define.
>> > * include/std/version (__cpp_lib_is_scoped_enum): Define.
>> > * testsuite/20_util/is_scoped_enum/value.cc: New test.
>> > * testsuite/20_util/is_scoped_enum/version.cc: New test.
>> >
>> > Tested powerpc64le-linux. Committed to trunk.
>> >
>>
>> Using __underlying_type breaks for incomplete enumeration types. GCC
>> doesn't have incomplete scoped enums due to
>> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89025 but unscoped ones
>> exist:
>>
>> enum E {
>> x = std::is_scoped_enum_v
>> };
>
>
> Thanks, I'll just use int then. Maybe not until Monday though.
>
>

Using int avoids the hard error, but it appears to give the wrong
answer (presumably because the is_convertible check fails due to E
being incomplete). This may need to be handled explicitly?


[committed] [PR99680] Check empty constraint before using CONSTRAINT_LEN.

2021-03-20 Thread Vladimir Makarov via Gcc-patches

The following patch fixes

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99680

The patch was successfully bootstrapped on x86-64.

commit c1ab0c0336d85f5e97739060ecf77fd05ac86d2a
Author: Vladimir N. Makarov 
Date:   Sat Mar 20 10:50:03 2021 -0400

[PR99680] Check empty constraint before using CONSTRAINT_LEN.

It seems CONSTRAINT_LEN treats constraint '\0' as one having length 1.  Therefore we
read after the constraint string.  The patch fixes it.

gcc/ChangeLog:

PR rtl-optimization/99680
* lra-constraints.c (skip_contraint_modifiers): Rename to skip_constraint_modifiers.
(process_address_1): Check empty constraint before using
CONSTRAINT_LEN.

diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c
index 698d8d04a1e..fdfe953bcf5 100644
--- a/gcc/lra-constraints.c
+++ b/gcc/lra-constraints.c
@@ -3395,12 +3395,12 @@ equiv_address_substitution (struct address_info *ad)
 /* Skip all modifiers and whitespaces in constraint STR and return the
result.  */
 static const char *
-skip_contraint_modifiers (const char *str)
+skip_constraint_modifiers (const char *str)
 {
   for (;;str++)
 switch (*str)
   {
-  case '+' : case '&' : case '=': case '*': case ' ': case '\t':
+  case '+': case '&' : case '=': case '*': case ' ': case '\t':
   case '$': case '^' : case '%': case '?': case '!':
 	break;
   default: return str;
@@ -3451,13 +3451,13 @@ process_address_1 (int nop, bool check_only_p,
 return false;
 
   constraint
-= skip_contraint_modifiers (curr_static_id->operand[nop].constraint);
+= skip_constraint_modifiers (curr_static_id->operand[nop].constraint);
   if (IN_RANGE (constraint[0], '0', '9'))
 {
   char *end;
   unsigned long dup = strtoul (constraint, &end, 10);
   constraint
-	= skip_contraint_modifiers (curr_static_id->operand[dup].constraint);
+	= skip_constraint_modifiers (curr_static_id->operand[dup].constraint);
 }
   cn = lookup_constraint (*constraint == '\0' ? "X" : constraint);
   /* If we have several alternatives or/and several constraints in an
@@ -3465,10 +3465,10 @@ process_address_1 (int nop, bool check_only_p,
  use unknown constraint.  The exception is an address constraint.  If
  operand has one address constraint, probably all others constraints are
  address ones.  */
-  if (get_constraint_type (cn) != CT_ADDRESS
-  && *skip_contraint_modifiers (constraint
-+ CONSTRAINT_LEN (constraint[0],
-		  constraint)) != '\0')
+  if (constraint[0] != '\0' && get_constraint_type (cn) != CT_ADDRESS
+  && *skip_constraint_modifiers (constraint
+ + CONSTRAINT_LEN (constraint[0],
+		   constraint)) != '\0')
 cn = CONSTRAINT__UNKNOWN;
   if (insn_extra_address_constraint (cn)
   /* When we find an asm operand with an address constraint that


Re: [PATCH] Fix typo in gcc/asan.c comment

2021-03-20 Thread Jeff Law via Gcc-patches



On 3/7/2021 4:10 PM, Ahamed Husni via Gcc-patches wrote:

Hi all,
 This is my first contribution for an open source project. Please guide
me if anything is missing.

diff --git a/gcc/gcc/asan.c b/gcc/gcc/asan.c
index 89ecd99b182..836f50bd44a 100755
--- a/gcc/gcc/asan.c
+++ b/gcc/gcc/asan.c
@@ -105,7 +105,7 @@ along with GCC; see the file COPYING3.  If not see
   int
   foo ()
   {
-   char a[23] = {0};
+   char a[24] = {0};
 int b[2] = {0};

 a[5] = 1;


Author: Husni Faiz 
Date:   Mon Mar 8 03:28:51 2021 +0530

 Fix typo in gcc/asan.c comment

 The size of the variable 'a' should be 24 bytes as mentioned in line
 no.126.


There's another instance a bit later in the file that I fixed as well.


Thanks,

Jeff



Re: enable sqrt insns for cdce3.c

2021-03-20 Thread Jeff Law via Gcc-patches



On 3/9/2021 11:30 PM, Alexandre Oliva wrote:

The test expects shrink-wrapping of the fsqrt call, but that will only
occur when there is a usable sqrt insn.

Arrange for dejagnu to add the options that enable the sqrt insn, if
one is available, and to skip the test otherwise.


H-P, this *should* obviate the mmix-specific dg-skip-if.  Would it be
easy for you to confirm that this is the case and, if so, drop it?

This was regstrapped on x86_64-linux-gnu, tested with a cross to a
ppc64-vxworks7r2 configured for a cpu that doesn't have fsqrt enabled,
and I'm now also regstrapping on ppc64-linux-gnu just to be sure.
Ok to install?


for  gcc/testsuite/ChangeLog

* gcc.dg/cdce3.c: Add sqrt insn options.


OK

jeff



Re: [PATCH] c-family: Fix PR94272 -fcompare-debug issue even for C [PR99230]

2021-03-20 Thread Jeff Law via Gcc-patches



On 3/18/2021 2:48 AM, Jakub Jelinek via Gcc-patches wrote:

Hi!

The following testcase results in -fcompare-debug failure.
The problem is the similar like in PR94272
https://gcc.gnu.org/pipermail/gcc-patches/2020-March/542562.html
When genericizing, with -g0 we have just a TREE_SIDE_EFFECTS DO_STMT
in a branch of if, while with -g we have that wrapped into
TREE_SIDE_EFFECTS STATEMENT_LIST containing DEBUG_BEGIN_STMT and that
DO_STMT.
The do loop is empty with 0 condition, so c_genericize_control_stmt
turns it into an empty statement (without TREE_SIDE_EFFECTS).
For -g0 that means that suddenly the if branch doesn't have side effects
and is expanded differently.  But with -g we still have TREE_SIDE_EFFECTS
STATEMENT_LIST containing DEBUG_BEGIN_STMT and non-TREE_SIDE_EFFECTS stmt.
The following patch fixes that by detecting this case and removing
TREE_SIDE_EFFECTS.

And, so that we don't duplicate the same code, changes the C++ FE to
just call the c_genericize_control_stmt function that can now handle it.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2021-03-18  Jakub Jelinek  

PR debug/99230
* c-gimplify.c (c_genericize_control_stmt): Handle STATEMENT_LIST.

* cp-gimplify.c (cp_genericize_r) : Remove
special code, instead call c_genericize_control_stmt.

* gcc.dg/pr99230.c: New test.


OK

jeff



Re: [PATCH] cprop_hardreg: Ensure replacement reg has compatible mode [PR99221]

2021-03-20 Thread Jeff Law via Gcc-patches



On 3/12/2021 10:54 AM, Stefan Schulze Frielinghaus via Gcc-patches wrote:

In addition to the existing check also ask the target whether a
replacement register may be accessed in a different mode than it was set
before.

Bootstrapped and regtested on IBM Z.  Ok for mainline?

gcc/ChangeLog:

* regcprop.c (find_oldest_value_reg): Ask target whether
  different mode is fine for replacement register.


OK

jeff



Re: 回复: [PATCH v4 1/2] MIPS: Not trigger error for pre-R6 and -mcompact-branches=always

2021-03-20 Thread Jeff Law via Gcc-patches



On 3/3/2021 8:33 PM, yunqiang...@cipunited.com wrote:

On 2/23/21 3:14 AM, YunQiang Su wrote:

For MIPSr6, we may wish to use compact-branches only.
Currently, we have to use `always' option, while it is mark as
conflict with pre-R6.
   cc1: error: unsupported combination: ‘mips32r2’
-mcompact-branches=always Just ignore -mcompact-branches=always for

pre-R6.

This patch also defines
 __mips_compact_branches_never
 __mips_compact_branches_always
 __mips_compact_branches_optimal
predefined macros

gcc/ChangeLog:
* config/mips/mips.c (mips_option_override):
* config/mips/mips.h (TARGET_RTP_PIC): not trigger error for
compact-branches=always for pre-R6.
(TARGET_CB_NEVER): Likewise.
(TARGET_CB_ALWAYS): Likewise.
(struct mips_cpu_info): define macros for compact branch policy.
* doc/invoke.texi: Document "always" with pre-R6.

gcc/testsuite/ChangeLog:
* gcc.target/mips/compact-branches-1.c: add isa_rev>=6.
* gcc.target/mips/mips.exp: don't add -mipsXXr6 option for
-mcompact-branches=always. It is usable for pre-R6 now.
* gcc.target/mips/compact-branches-8.c: New test.
* gcc.target/mips/compact-branches-9.c: New test.

So I think Maciej's comment was that you simply shouldn't be using
-mcompact-branches=always at mips32r2 (or anything pre-r6) together.

I think what you're trying to do here is set up a scenario where you're
defaulting to mips32r6 and compact-branches, but not error if something
specifies -mcpu=mips32r2 or something similar, right?


Yes. If we introduce the build time option, and configure gcc with always, then 
gcc will always try to
Pass -mconpact-branches=always to cc1, even we use something like:
 mipsisa32r6el-linux-gnu-gcc -mips32r2 -c xx.c
It may break something.


So would it be possible to make the mips32rX (for X <6) option also turn 
off compact-branches?   Maciej, is that less problematical from your 
standpoint?  Or is this just ultimately a bad idea from start to finish?



Jeff



[PATCH v2] x86: Check cfun != NULL before accessing silent_p

2021-03-20 Thread H.J. Lu via Gcc-patches
On Sat, Mar 20, 2021 at 6:46 AM Martin Liška  wrote:
>
> On 3/20/21 1:21 PM, H.J. Lu wrote:
> > |Since construct_container may be called with cfun == NULL, check cfun != 
> > NULL before accessing silent_p. |
>
> Thank you for the quick fix.
>
> Please use the minimal reproducer for a test-case:
>
> $ cat va-arg-pack-1.C
> #include 
> void abort() {
>double ld;
>va_list ap;
>ld = va_arg(ap, long double);
>if (ld)
>  abort();
> }
>

Fixed.  I also added a testcase for SSE register.

Here is the v2 patch.  OK for master?

Thanks.

-- 
H.J.
From 5abf5691a075a9e992b527a1f1a3018b68ac8768 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" 
Date: Sat, 20 Mar 2021 05:17:36 -0700
Subject: [PATCH v2] x86: Check cfun != NULL before accessing silent_p

Since construct_container may be called with cfun == NULL, check
cfun != NULL before accessing silent_p.

gcc/

	PR target/99679
	* config/i386/i386.c (construct_container): Check cfun != NULL
	before accessing silent_p.

gcc/testsuite/

	PR target/99679
	* g++.target/i386/pr99679-1.C: New test.
	* g++.target/i386/pr99679-2.C: Likewise.
---
 gcc/config/i386/i386.c|  4 ++--
 gcc/testsuite/g++.target/i386/pr99679-1.C | 17 +
 gcc/testsuite/g++.target/i386/pr99679-2.C | 17 +
 3 files changed, 36 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.target/i386/pr99679-1.C
 create mode 100644 gcc/testsuite/g++.target/i386/pr99679-2.C

diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 714349094bd..7c41302c75b 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -2540,7 +2540,7 @@ construct_container (machine_mode mode, machine_mode orig_mode,
 {
   /* Return early if we shouldn't raise an error for invalid
 	 calls.  */
-  if (cfun->machine->silent_p)
+  if (cfun != NULL && cfun->machine->silent_p)
 	return NULL;
   if (in_return)
 	{
@@ -2568,7 +2568,7 @@ construct_container (machine_mode mode, machine_mode orig_mode,
 	{
 	  /* Return early if we shouldn't raise an error for invalid
 	 calls.  */
-	  if (cfun->machine->silent_p)
+	  if (cfun != NULL && cfun->machine->silent_p)
 	return NULL;
 	  if (!issued_x87_ret_error)
 	{
diff --git a/gcc/testsuite/g++.target/i386/pr99679-1.C b/gcc/testsuite/g++.target/i386/pr99679-1.C
new file mode 100644
index 000..36640a4e0a1
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/pr99679-1.C
@@ -0,0 +1,17 @@
+// { dg-do compile }
+// { dg-options "-Ofast -fipa-pta -mno-80387" }
+
+#include 
+
+extern "C" void abort (void);
+
+void
+foo (int x, ...)
+{
+  long double ld;
+  va_list ap;
+  va_start (ap, x);
+  ld = va_arg (ap, long double);
+  if (ld)
+abort ();
+} // { dg-error "x87 register return with x87 disabled" "" { target { ! ia32 } } }
diff --git a/gcc/testsuite/g++.target/i386/pr99679-2.C b/gcc/testsuite/g++.target/i386/pr99679-2.C
new file mode 100644
index 000..cbd3c4958db
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/pr99679-2.C
@@ -0,0 +1,17 @@
+// { dg-do compile }
+// { dg-options "-Ofast -fipa-pta -mgeneral-regs-only" }
+
+#include 
+
+extern "C" void abort (void);
+
+void
+foo (int x, ...)
+{
+  double ld;
+  va_list ap;
+  va_start (ap, x);
+  ld = va_arg (ap, double); // { dg-error "SSE register argument with SSE disabled" "" { target { ! ia32 } } }
+  if (ld)
+abort ();
+} // { dg-error "SSE register return with SSE disabled" "" { target { ! ia32 } } }
-- 
2.30.2



[PATCH 01/24] Add -gcodeview debugging option

2021-03-20 Thread Mark Harmstone
This is a series of patches to allow gcc to emit debugging information
in the PE-specific CodeView format, which allows Microsoft debuggers to
work with mingw EXEs. The format is semi-documented: Microsoft have
open-sourced some of their header files at
https://github.com/microsoft/microsoft-pdb, along with a program
cvdump.exe which outputs the textual form of the data.

This works by adding two new sections to every object file: .debug$T,
which contains the type definitions, and .debug$S, which is everything
else (line numbers, file checksums, symbols). The linker then merges
everything together, resolves any duplicate types etc., and outputs this
as a PDB file. Obviously this needs linker support to be useful - lld
does the job, or you can try my binutils patches at
https://github.com/maharmstone/binutils-gdb/tree/for-gcc.

It also needs support for the asm-pseudo directive .secidx, which
outputs the IMAGE_REL_AMD64_SECTION / IMAGE_REL_I386_SECTION PE
relocations. This is likewise not in mainstream binutils - you can
either try llvm-mc instead of gas, or my binutils repo above.

In terms of debuggers and the like, I've tested this successfully with
Visual Studio, windbg, radare2, and of course the aforementioned cvdump
- I don't think there's any other significant tools which use the
 format.

I've only tested this on x86 and amd64, as I've no idea how you go about
compiling Windows EXEs for arm or aarch64 with gcc, or if such a thing
is possible. The other architectures the format provides for are 16-bit
x86, alpha, mips, m68k, ppc, sh3, arm, aarch64, and ia64 - adding these
would at the very least require updating the register mapping.

If you're looking to test this, Wine makes a good victim: set
CROSSCFLAGS to "-gcodeview" when configuring. You probably also want to
set CFLAGS_FOR_TARGET and CXXFLAGS_FOR_TARGET to "-gcodeview" when
configuring gcc, to make sure that debugging information gets generated
for libgcc etc.

---
 gcc/Makefile.in   |  3 ++
 gcc/common.opt|  4 +++
 gcc/config/i386/cygming.h |  1 +
 gcc/config/i386/x86-64.h  |  2 ++
 gcc/debug.h   |  1 +
 gcc/defaults.h|  3 ++
 gcc/doc/invoke.texi   |  7 
 gcc/flag-types.h  |  5 +--
 gcc/gcc.c |  6 
 gcc/opts.c|  4 +++
 gcc/pdbout.c  | 70 +++
 gcc/pdbout.h  | 23 +
 gcc/toplev.c  |  4 +++
 13 files changed, 131 insertions(+), 2 deletions(-)
 create mode 100644 gcc/pdbout.c
 create mode 100644 gcc/pdbout.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 543b477ff18..f0249bde720 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1476,6 +1476,7 @@ OBJS = \
opts-global.o \
ordered-hash-map-tests.o \
passes.o \
+   pdbout.o \
plugin.o \
postreload-gcse.o \
postreload.o \
@@ -2637,6 +2638,8 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h 
$(srcdir)/coretypes.h \
   $(srcdir)/hsa-common.c \
   $(srcdir)/calls.c \
   $(srcdir)/omp-general.h \
+  $(srcdir)/pdbout.c \
+  $(srcdir)/pdbout.h \
   @all_gtfiles@
 
 # Compute the list of GT header files from the corresponding C sources,
diff --git a/gcc/common.opt b/gcc/common.opt
index d33383b523c..80c488c0d70 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3127,6 +3127,10 @@ gno-pubnames
 Common Driver Negative(gpubnames) Var(debug_generate_pub_sections, 0) Init(-1)
 Don't generate DWARF pubnames and pubtypes sections.
 
+gcodeview
+Common Driver JoinedOrMissing
+Generate debug information in CodeView format.
+
 gpubnames
 Common Driver Negative(ggnu-pubnames) Var(debug_generate_pub_sections, 1)
 Generate DWARF pubnames and pubtypes sections.
diff --git a/gcc/config/i386/cygming.h b/gcc/config/i386/cygming.h
index 1b1ea7d3d8a..42191b16c99 100644
--- a/gcc/config/i386/cygming.h
+++ b/gcc/config/i386/cygming.h
@@ -19,6 +19,7 @@ along with GCC; see the file COPYING3.  If not see
 .  */
 
 #define DBX_DEBUGGING_INFO 1
+#define PDB_DEBUGGING_INFO 1
 #if TARGET_64BIT_DEFAULT || defined (HAVE_GAS_PE_SECREL32_RELOC)
 #define DWARF2_DEBUGGING_INFO 1
 #endif
diff --git a/gcc/config/i386/x86-64.h b/gcc/config/i386/x86-64.h
index 88db428f592..e84ee6c4026 100644
--- a/gcc/config/i386/x86-64.h
+++ b/gcc/config/i386/x86-64.h
@@ -91,6 +91,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If 
not, see
 #define DWARF2_DEBUGGING_INFO 1
 #define DWARF2_UNWIND_INFO 1
 
+#define PDB_DEBUGGING_INFO 1
+
 #undef PREFERRED_DEBUGGING_TYPE
 #define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
 
diff --git a/gcc/debug.h b/gcc/debug.h
index 260325920ea..c8f182962dd 100644
--- a/gcc/debug.h
+++ b/gcc/debug.h
@@ -235,6 +235,7 @@ extern const struct gcc_debug_hooks xcoff_debug_hooks;
 extern const struct gcc_debug_hooks dwarf2_debug_hooks;
 extern const struct gcc_debug_hooks dwarf2_lineno_debug_hooks;
 extern const struct gcc_debug_hooks vmsdbg_debug_hooks;
+exter

[PATCH 03/24] pdbout: Output function details.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 149 +--
 gcc/pdbout.h |  12 +
 2 files changed, 158 insertions(+), 3 deletions(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index feaab37cc37..17011134d7a 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -29,14 +29,25 @@
 #include "tree.h"
 #include "debug.h"
 #include "pdbout.h"
+#include "function.h"
 #include "output.h"
 #include "target.h"
 
+#define FUNC_BEGIN_LABEL   ".Lstartfunc"
+#define FUNC_END_LABEL ".Lendfunc"
+
+static void pdbout_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
+  unsigned int column ATTRIBUTE_UNUSED,
+  const char *file ATTRIBUTE_UNUSED);
+static void pdbout_end_epilogue (unsigned int line ATTRIBUTE_UNUSED,
+const char *file ATTRIBUTE_UNUSED);
 static void pdbout_finish (const char *filename);
+static void pdbout_begin_function (tree func);
 static void pdbout_late_global_decl (tree var);
 
 static struct pdb_type *find_type (tree t);
 
+static struct pdb_func *funcs = NULL, *cur_func = NULL;
 static struct pdb_global_var *global_vars = NULL;
 static struct pdb_type *types = NULL, *last_type = NULL;
 static hash_table  tree_hash_table (31);
@@ -66,11 +77,11 @@ const struct gcc_debug_hooks pdb_debug_hooks = {
   debug_nothing_int_int,   /* end_block */
   debug_true_const_tree,   /* ignore_block */
   debug_nothing_int_int_charstar_int_bool, /* source_line */
-  debug_nothing_int_int_charstar,  /* begin_prologue */
+  pdbout_begin_prologue,
   debug_nothing_int_charstar,  /* end_prologue */
   debug_nothing_int_charstar,  /* begin_epilogue */
-  debug_nothing_int_charstar,  /* end_epilogue */
-  debug_nothing_tree,  /* begin_function */
+  pdbout_end_epilogue,
+  pdbout_begin_function,
   debug_nothing_int,   /* end_function */
   debug_nothing_tree,  /* register_main_translation_unit */
   debug_nothing_tree,  /* function_decl */
@@ -93,6 +104,84 @@ const struct gcc_debug_hooks pdb_debug_hooks = {
   TYPE_SYMTAB_IS_ADDRESS   /* tree_type_symtab_field */
 };
 
+/* Add label before function start */
+static void
+pdbout_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
+  unsigned int column ATTRIBUTE_UNUSED,
+  const char *file ATTRIBUTE_UNUSED)
+{
+  fprintf (asm_out_file, FUNC_BEGIN_LABEL "%u:\n",
+  current_function_funcdef_no);
+}
+
+/* Add label after function end */
+static void
+pdbout_end_epilogue (unsigned int line ATTRIBUTE_UNUSED,
+const char *file ATTRIBUTE_UNUSED)
+{
+  fprintf (asm_out_file, FUNC_END_LABEL "%u:\n", current_function_funcdef_no);
+}
+
+/* Output PROCSYM32 structure, which describes a global function (S_GPROC32)
+ * or a local (i.e. static) one (S_LPROC32). */
+static void
+pdbout_proc32 (struct pdb_func *func)
+{
+  size_t name_len = func->name ? strlen (func->name) : 0;
+  uint16_t len = 40 + name_len, align;
+
+  // start procedure
+
+  if (len % 4 != 0)
+{
+  align = 4 - (len % 4);
+  len += 4 - (len % 4);
+}
+  else
+align = 0;
+
+  fprintf (asm_out_file, ".Lcvprocstart%u:\n", func->num);
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+  (uint16_t) (len - sizeof (uint16_t)));   // reclen
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+  func->public_flag ? S_GPROC32 : S_LPROC32);
+  fprintf (asm_out_file, "\t.long\t0\n");  // pParent
+  fprintf (asm_out_file, "\t.long\t[.Lcvprocend%u]-[.debug$S]\n",
+  func->num);  // pEnd
+  fprintf (asm_out_file, "\t.long\t0\n");  // pNext
+  fprintf (asm_out_file,
+  "\t.long\t[" FUNC_END_LABEL "%u]-[" FUNC_BEGIN_LABEL "%u]\n",
+  func->num, func->num);   // len
+  fprintf (asm_out_file, "\t.long\t0\n");  // DbgStart
+  fprintf (asm_out_file, "\t.long\t0\n");  // DbgEnd
+  fprintf (asm_out_file, "\t.short\t0x%x\n", func->type ? func->type->id : 0);
+  fprintf (asm_out_file, "\t.short\t0\n"); // padding
+
+  fprintf (asm_out_file, "\t.secrel32\t" FUNC_BEGIN_LABEL "%u\n",
+  func->num);  // offset
+  fprintf (asm_out_file, "\t.secidx\t" FUNC_BEGIN_LABEL "%u\n",
+  func->num);  // section
+
+  fprintf (asm_out_file, "\t.byte\t0\n");  // flags
+
+  if (func->name)
+ASM_OUTPUT_ASCII (asm_out_file, func->name, name_len + 1);
+  else
+fprintf (asm_out_file, "\t.byte\t0\n");
+
+  for (unsigned int i = 0; i < align; i++)
+{
+  fprintf (asm_out_file, "\t.byte\t0\n");
+}
+
+  // end procedure
+
+  fprintf (asm_out_file, ".Lcvprocend%u:\n", func->num);
+
+  fprintf (asm_out_file, "\t.short\t0x2\n");
+  fprintf (asm_out_file, "\t.short\t0x%x\n", S_END);
+}
+
 /* Output DATASYM32 structure, describing a global variable: either
  * one with file-level scope (S_LDATA32) or global scope (S_GDATA32). */
 static void
@@ -138,6 +227,8 @@ pdbout_data32 (struct pdb_global_var *v)
 static void
 write_pdb_sec

[PATCH 02/24] pdbout: Output details of local variables.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 417 ++-
 gcc/pdbout.h |  89 +++
 2 files changed, 504 insertions(+), 2 deletions(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index e8f39bb64ea..feaab37cc37 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -25,13 +25,37 @@
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "varasm.h"
 #include "tree.h"
 #include "debug.h"
 #include "pdbout.h"
+#include "output.h"
+#include "target.h"
+
+static void pdbout_finish (const char *filename);
+static void pdbout_late_global_decl (tree var);
+
+static struct pdb_type *find_type (tree t);
+
+static struct pdb_global_var *global_vars = NULL;
+static struct pdb_type *types = NULL, *last_type = NULL;
+static hash_table  tree_hash_table (31);
+static struct pdb_type *byte_type, *signed_byte_type, *wchar_type,
+  *char16_type, *uint16_type, *int16_type, *char32_type, *uint32_type,
+  *int32_type, *uint64_type, *int64_type, *uint128_type, *int128_type,
+  *long_type, *ulong_type, *hresult_type;
+static struct pdb_type *float16_type, *float32_type, *float48_type,
+  *float64_type, *float80_type, *float128_type;
+static struct pdb_type *bool8_type, *bool16_type, *bool32_type, *bool64_type,
+  *bool128_type;
+static struct pdb_type *complex16_type, *complex32_type, *complex48_type,
+  *complex64_type, *complex80_type, *complex128_type;
+static struct pdb_type *void_type, *nullptr_type;
+static bool builtins_initialized = false;
 
 const struct gcc_debug_hooks pdb_debug_hooks = {
   debug_nothing_charstar,  /* init */
-  debug_nothing_charstar,  /* finish */
+  pdbout_finish,
   debug_nothing_charstar,  /* early_finish */
   debug_nothing_void,  /* assembly_start */
   debug_nothing_int_charstar,  /* define */
@@ -51,7 +75,7 @@ const struct gcc_debug_hooks pdb_debug_hooks = {
   debug_nothing_tree,  /* register_main_translation_unit */
   debug_nothing_tree,  /* function_decl */
   debug_nothing_tree,  /* early_global_decl */
-  debug_nothing_tree,  /* late_global_decl */
+  pdbout_late_global_decl,
   debug_nothing_tree_int,  /* type_decl */
   debug_nothing_tree_tree_tree_bool_bool,  /* imported_module_or_decl */
   debug_false_tree_charstarstar_uhwistar,  /* die_ref_for_decl */
@@ -68,3 +92,392 @@ const struct gcc_debug_hooks pdb_debug_hooks = {
   0,   /* start_end_main_source_file */
   TYPE_SYMTAB_IS_ADDRESS   /* tree_type_symtab_field */
 };
+
+/* Output DATASYM32 structure, describing a global variable: either
+ * one with file-level scope (S_LDATA32) or global scope (S_GDATA32). */
+static void
+pdbout_data32 (struct pdb_global_var *v)
+{
+  size_t name_len = strlen (v->name);
+  uint16_t len;
+
+  // Outputs DATASYM32 struct
+
+  len = 15 + name_len;
+
+  if (len % 4 != 0)
+len += 4 - (len % 4);
+
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+  (uint16_t) (len - sizeof (uint16_t)));   // reclen
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+  v->public_flag ? S_GDATA32 : S_LDATA32);
+  fprintf (asm_out_file, "\t.short\t0x%x\n", v->type ? v->type->id : 0);
+  fprintf (asm_out_file, "\t.short\t0\n");
+
+  fprintf (asm_out_file, "\t.secrel32\t"); // off
+  ASM_OUTPUT_LABELREF (asm_out_file, v->asm_name);
+  fprintf (asm_out_file, "\n");
+  fprintf (asm_out_file, "\t.secidx\t");   // section
+  ASM_OUTPUT_LABELREF (asm_out_file, v->asm_name);
+  fprintf (asm_out_file, "\n");
+
+  ASM_OUTPUT_ASCII (asm_out_file, v->name, name_len + 1);
+
+  fprintf (asm_out_file, "\t.balign\t4\n");
+}
+
+/* Output the .debug$S section, which has everything except the
+ * type definitions (global variables, functions, string table,
+ * file checksums, line numbers).
+ * The linker will extract this section from all the object
+ * files, remove any duplicate data, resolve all addresses,
+ * and output the resulting data into a PDB file. The section's
+ * marked as "ndr", so even if the linker doesn't understand it,
+ * the section won't make its way into final binary. */
+static void
+write_pdb_section (void)
+{
+  fprintf (asm_out_file, "\t.section\t.debug$S, \"ndr\"\n");
+  fprintf (asm_out_file, "\t.long\t0x%x\n", CV_SIGNATURE_C13);
+  fprintf (asm_out_file, "\t.long\t0x%x\n", DEBUG_S_SYMBOLS);
+  fprintf (asm_out_file, "\t.long\t[.Lsymend]-[.Lsymstart]\n");
+
+  fprintf (asm_out_file, ".Lsymstart:\n");
+
+  while (global_vars)
+{
+  struct pdb_global_var *n;
+
+  pdbout_data32 (global_vars);
+
+  n = global_vars->next;
+
+  if (global_vars->name)
+   free (global_vars->name);
+
+  if (global_vars->asm_name)
+   free (global_vars->asm_name);
+
+  free (global_vars);
+
+  global_vars = n;
+}
+
+  fprintf (asm_out_file, ".Lsymend:\n");
+}
+
+/* We've finished compilation - output the .debug$S section
+ * to the asm file. */
+static void
+pdbout_finish (const char *filename ATTRIBUTE_UNUSED)
+{
+  write_pdb_section ();
+}
+

[PATCH 05/24] pdbout: Handle optimized variables.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 242 ++-
 gcc/pdbout.h |  21 +
 2 files changed, 260 insertions(+), 3 deletions(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index 2f5b52b6fc3..29b0d1c131f 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -51,6 +51,7 @@ static void pdbout_finish (const char *filename);
 static void pdbout_begin_function (tree func);
 static void pdbout_late_global_decl (tree var);
 static void pdbout_function_decl (tree decl);
+static void pdbout_var_location (rtx_insn * loc_note);
 static void pdbout_begin_block (unsigned int line ATTRIBUTE_UNUSED,
unsigned int blocknum);
 static void pdbout_end_block (unsigned int line ATTRIBUTE_UNUSED,
@@ -62,6 +63,7 @@ static struct pdb_func *funcs = NULL, *cur_func = NULL;
 static struct pdb_block *cur_block = NULL;
 static struct pdb_global_var *global_vars = NULL;
 static struct pdb_type *types = NULL, *last_type = NULL;
+static unsigned int var_loc_number = 1;
 static hash_table  tree_hash_table (31);
 static struct pdb_type *byte_type, *signed_byte_type, *wchar_type,
   *char16_type, *uint16_type, *int16_type, *char32_type, *uint32_type,
@@ -107,7 +109,7 @@ const struct gcc_debug_hooks pdb_debug_hooks = {
   debug_nothing_tree,  /* outlining_inline_function */
   debug_nothing_rtx_code_label,/* label */
   debug_nothing_int,   /* handle_pch */
-  debug_nothing_rtx_insn,  /* var_location */
+  pdbout_var_location,
   debug_nothing_tree,  /* inline_entry */
   debug_nothing_tree,  /* size_function */
   debug_nothing_void,  /* switch_text_section */
@@ -134,12 +136,143 @@ pdbout_end_epilogue (unsigned int line ATTRIBUTE_UNUSED,
   fprintf (asm_out_file, FUNC_END_LABEL "%u:\n", current_function_funcdef_no);
 }
 
+/* Output DEFRANGESYMREGISTER or DEFRANGESYMREGISTERREL structure, describing
+ * the scope range, register, and offset at which a local variable can be
+ * found. */
+static void
+write_var_location (struct pdb_var_location *var_loc,
+   unsigned int next_var_loc_number, unsigned int func_num)
+{
+  switch (var_loc->type)
+{
+case pdb_var_loc_register:
+  fprintf (asm_out_file, "\t.short\t0xe\n");
+  fprintf (asm_out_file, "\t.short\t0x%x\n", S_DEFRANGE_REGISTER);
+  fprintf (asm_out_file, "\t.short\t0x%x\n", var_loc->reg);
+  fprintf (asm_out_file, "\t.short\t0\n"); // range attr
+  fprintf (asm_out_file, "\t.secrel32\t.Lvarloc%u\n",
+  var_loc->var_loc_number);
+  fprintf (asm_out_file, "\t.secidx\t.Lvarloc%u\n",
+  var_loc->var_loc_number);
+
+  if (next_var_loc_number != 0)
+   {
+ fprintf (asm_out_file, "\t.short\t[.Lvarloc%u]-[.Lvarloc%u]\n",
+  next_var_loc_number, var_loc->var_loc_number);
+   }
+  else
+   {
+ fprintf (asm_out_file,
+  "\t.short\t[" FUNC_END_LABEL "%u]-[.Lvarloc%u]\n",
+  func_num, var_loc->var_loc_number);  // to end of function
+   }
+
+  break;
+
+case pdb_var_loc_regrel:
+  fprintf (asm_out_file, "\t.short\t0x12\n");
+  fprintf (asm_out_file, "\t.short\t0x%x\n", S_DEFRANGE_REGISTER_REL);
+  fprintf (asm_out_file, "\t.short\t0x%x\n", var_loc->reg);
+
+  // spilledUdtMember, padding, offsetParent
+  fprintf (asm_out_file, "\t.short\t0\n");
+
+  fprintf (asm_out_file, "\t.long\t0x%x\n", var_loc->offset);
+  fprintf (asm_out_file, "\t.secrel32\t.Lvarloc%u\n",
+  var_loc->var_loc_number);
+  fprintf (asm_out_file, "\t.secidx\t.Lvarloc%u\n",
+  var_loc->var_loc_number);
+
+  if (next_var_loc_number != 0)
+   {
+ fprintf (asm_out_file, "\t.short\t[.Lvarloc%u]-[.Lvarloc%u]\n",
+  next_var_loc_number, var_loc->var_loc_number);
+   }
+  else
+   {
+ fprintf (asm_out_file,
+  "\t.short\t[" FUNC_END_LABEL "%u]-[.Lvarloc%u]\n",
+  func_num, var_loc->var_loc_number);  // to end of function
+   }
+
+  break;
+
+case pdb_var_loc_unknown:
+  break;
+}
+}
+
+/* We have encountered an optimized local variable, i.e. one which doesn't
+ * live in the same place for the duration of a function.
+ * Output a LOCALSYM struct. */
+static void
+pdbout_optimized_local_variable (struct pdb_local_var *v,
+struct pdb_var_location *var_locs,
+unsigned int func_num)
+{
+  uint16_t len, align;
+  size_t name_len = strlen (v->name);
+  struct pdb_var_location *last_pvl = var_locs, *pvl;
+
+  len = 11 + name_len;
+
+  if (len % 4 != 0)
+{
+  align = 4 - (len % 4);
+  len += 4 - (len % 4);
+}
+  else
+align = 0;
+
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+  (uint16_t) (len - sizeof (uint16_t)));
+  fprintf (asm_out_file, "\t.short\t0x%x\n", S_LOCAL);
+  fprintf (asm_out_file, "\t.long\t0x%x\n", v->type ? v->type-

[PATCH 07/24] pdbout: Output line numbers.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 150 ++-
 gcc/pdbout.h |  10 
 2 files changed, 159 insertions(+), 1 deletion(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index a4424fa470d..040ac6fe8e4 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -54,6 +54,11 @@ static void pdbout_begin_function (tree func);
 static void pdbout_late_global_decl (tree var);
 static void pdbout_start_source_file (unsigned int line ATTRIBUTE_UNUSED,
  const char *file);
+static void pdbout_source_line (unsigned int line,
+   unsigned int column ATTRIBUTE_UNUSED,
+   const char *text,
+   int discriminator ATTRIBUTE_UNUSED,
+   bool is_stmt ATTRIBUTE_UNUSED);
 static void pdbout_function_decl (tree decl);
 static void pdbout_var_location (rtx_insn * loc_note);
 static void pdbout_begin_block (unsigned int line ATTRIBUTE_UNUSED,
@@ -69,6 +74,7 @@ static struct pdb_global_var *global_vars = NULL;
 static struct pdb_type *types = NULL, *last_type = NULL;
 static struct pdb_source_file *source_files = NULL, *last_source_file = NULL;
 static uint32_t source_file_string_offset = 1;
+static unsigned int num_line_number_entries = 0;
 static unsigned int num_source_files = 0;
 static unsigned int var_loc_number = 1;
 static hash_table  tree_hash_table (31);
@@ -97,7 +103,7 @@ const struct gcc_debug_hooks pdb_debug_hooks = {
   pdbout_begin_block,
   pdbout_end_block,
   debug_true_const_tree,   /* ignore_block */
-  debug_nothing_int_int_charstar_int_bool, /* source_line */
+  pdbout_source_line,
   pdbout_begin_prologue,
   debug_nothing_int_charstar,  /* end_prologue */
   debug_nothing_int_charstar,  /* begin_epilogue */
@@ -617,6 +623,88 @@ write_file_checksums ()
   fprintf (asm_out_file, ".Lchksumsend:\n");
 }
 
+/* Loop through each function, and output the line number to
+ * address mapping. */
+static void
+write_line_numbers ()
+{
+  struct pdb_func *func = funcs;
+  unsigned int lines_part = 0;
+
+  while (func)
+{
+  while (func->lines)
+   {
+ struct pdb_line *l, *last_line;
+ unsigned int num_entries = 0, source_file, first_entry;
+
+ source_file = func->lines->source_file;
+
+ l = last_line = func->lines;
+ while (l && l->source_file == source_file)
+   {
+ num_entries++;
+ last_line = l;
+ l = l->next;
+   }
+
+ first_entry = func->lines->entry;
+
+ fprintf (asm_out_file, "\t.long\t0x%x\n", DEBUG_S_LINES);
+ fprintf (asm_out_file, "\t.long\t[.Llinesend%u]-[.Llinesstart%u]\n",
+  lines_part, lines_part);
+ fprintf (asm_out_file, ".Llinesstart%u:\n", lines_part);
+
+ // offset
+ fprintf (asm_out_file, "\t.secrel32\t.Lline%u\n", first_entry);
+ // section
+ fprintf (asm_out_file, "\t.secidx\t.Lline%u\n", first_entry);
+
+ fprintf (asm_out_file, "\t.short\t0\n");  // flags
+
+ // next section of function is another source file
+ if (last_line->next)
+   {
+ fprintf (asm_out_file, "\t.long\t[.Lline%u]-[.Lline%u]\n",
+  last_line->next->entry, first_entry);// length
+   }
+ else
+   {
+ fprintf (asm_out_file,
+  "\t.long\t[" FUNC_END_LABEL "%u]-[.Lline%u]\n",
+  func->num, first_entry); // length
+   }
+
+ // file ID (0x18 is size of checksum struct)
+ fprintf (asm_out_file, "\t.long\t0x%x\n", source_file * 0x18);
+ fprintf (asm_out_file, "\t.long\t0x%x\n", num_entries);
+ // length of file block
+ fprintf (asm_out_file, "\t.long\t0x%x\n", 0xc + (num_entries * 8));
+
+ while (func->lines && func->lines->source_file == source_file)
+   {
+ struct pdb_line *n = func->lines->next;
+
+ // offset
+ fprintf (asm_out_file, "\t.long\t[.Lline%u]-[.Lline%u]\n",
+  func->lines->entry, first_entry);
+
+ // line no.
+ fprintf (asm_out_file, "\t.long\t0x%x\n", func->lines->line);
+
+ free (func->lines);
+
+ func->lines = n;
+   }
+
+ fprintf (asm_out_file, ".Llinesend%u:\n", lines_part);
+ lines_part++;
+   }
+
+  func = func->next;
+}
+}
+
 /* Output the .debug$S section, which has everything except the
  * type definitions (global variables, functions, string table,
  * file checksums, line numbers).
@@ -688,6 +776,8 @@ write_pdb_section (void)
 
   write_file_checksums ();
 
+  write_line_numbers ();
+
   while (funcs)
 {
   struct pdb_func *n = funcs->next;
@@ -728,6 +818,7 @@ get_tree_name (tree t)
 static void
 pdbout_begin_function (tree func)
 {
+  expanded_location xloc;
   struct pdb_func *f = (struct pdb_func *) xmal

[PATCH 06/24] pdbout: Output checksums and names of source files.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 195 ++-
 gcc/pdbout.h |  16 +
 2 files changed, 209 insertions(+), 2 deletions(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index 29b0d1c131f..a4424fa470d 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -32,6 +32,7 @@
 #include "function.h"
 #include "output.h"
 #include "target.h"
+#include "md5.h"
 #include "rtl.h"
 #include "insn-config.h"
 #include "reload.h"
@@ -47,9 +48,12 @@ static void pdbout_begin_prologue (unsigned int line 
ATTRIBUTE_UNUSED,
   const char *file ATTRIBUTE_UNUSED);
 static void pdbout_end_epilogue (unsigned int line ATTRIBUTE_UNUSED,
 const char *file ATTRIBUTE_UNUSED);
+static void pdbout_init (const char *filename);
 static void pdbout_finish (const char *filename);
 static void pdbout_begin_function (tree func);
 static void pdbout_late_global_decl (tree var);
+static void pdbout_start_source_file (unsigned int line ATTRIBUTE_UNUSED,
+ const char *file);
 static void pdbout_function_decl (tree decl);
 static void pdbout_var_location (rtx_insn * loc_note);
 static void pdbout_begin_block (unsigned int line ATTRIBUTE_UNUSED,
@@ -63,6 +67,9 @@ static struct pdb_func *funcs = NULL, *cur_func = NULL;
 static struct pdb_block *cur_block = NULL;
 static struct pdb_global_var *global_vars = NULL;
 static struct pdb_type *types = NULL, *last_type = NULL;
+static struct pdb_source_file *source_files = NULL, *last_source_file = NULL;
+static uint32_t source_file_string_offset = 1;
+static unsigned int num_source_files = 0;
 static unsigned int var_loc_number = 1;
 static hash_table  tree_hash_table (31);
 static struct pdb_type *byte_type, *signed_byte_type, *wchar_type,
@@ -79,13 +86,13 @@ static struct pdb_type *void_type, *nullptr_type;
 static bool builtins_initialized = false;
 
 const struct gcc_debug_hooks pdb_debug_hooks = {
-  debug_nothing_charstar,  /* init */
+  pdbout_init,
   pdbout_finish,
   debug_nothing_charstar,  /* early_finish */
   debug_nothing_void,  /* assembly_start */
   debug_nothing_int_charstar,  /* define */
   debug_nothing_int_charstar,  /* undef */
-  debug_nothing_int_charstar,  /* start_source_file */
+  pdbout_start_source_file,
   debug_nothing_int,   /* end_source_file */
   pdbout_begin_block,
   pdbout_end_block,
@@ -576,6 +583,40 @@ pdbout_data32 (struct pdb_global_var *v)
   fprintf (asm_out_file, "\t.balign\t4\n");
 }
 
+/* Output names of the files which make up this translation unit,
+ * along with their MD5 checksums. */
+static void
+write_file_checksums ()
+{
+  fprintf (asm_out_file, "\t.long\t0x%x\n", DEBUG_S_FILECHKSMS);
+  fprintf (asm_out_file, "\t.long\t[.Lchksumsend]-[.Lchksumsstart]\n");
+  fprintf (asm_out_file, ".Lchksumsstart:\n");
+
+  while (source_files)
+{
+  struct pdb_source_file *n;
+
+  fprintf (asm_out_file, "\t.long\t0x%x\n", source_files->str_offset);
+  fprintf (asm_out_file, "\t.byte\t0x%x\n", 16);   // length of MD5 hash
+  fprintf (asm_out_file, "\t.byte\t0x%x\n", CHKSUM_TYPE_MD5);
+
+  for (unsigned int i = 0; i < 16; i++)
+   {
+ fprintf (asm_out_file, "\t.byte\t0x%x\n", source_files->hash[i]);
+   }
+
+  fprintf (asm_out_file, "\t.short\t0\n");
+
+  n = source_files->next;
+
+  free (source_files);
+
+  source_files = n;
+}
+
+  fprintf (asm_out_file, ".Lchksumsend:\n");
+}
+
 /* Output the .debug$S section, which has everything except the
  * type definitions (global variables, functions, string table,
  * file checksums, line numbers).
@@ -587,6 +628,7 @@ pdbout_data32 (struct pdb_global_var *v)
 static void
 write_pdb_section (void)
 {
+  struct pdb_source_file *psf;
   struct pdb_func *func;
 
   fprintf (asm_out_file, "\t.section\t.debug$S, \"ndr\"\n");
@@ -625,6 +667,27 @@ write_pdb_section (void)
 
   fprintf (asm_out_file, ".Lsymend:\n");
 
+  fprintf (asm_out_file, "\t.long\t0x%x\n", DEBUG_S_STRINGTABLE);
+  fprintf (asm_out_file, "\t.long\t[.Lstrtableend]-[.Lstrtablestart]\n");
+  fprintf (asm_out_file, ".Lstrtablestart:\n");
+  fprintf (asm_out_file, "\t.byte\t0\n");
+
+  psf = source_files;
+  while (psf)
+{
+  size_t name_len = strlen (psf->name);
+
+  ASM_OUTPUT_ASCII (asm_out_file, psf->name + name_len + 1,
+   strlen (psf->name + name_len + 1) + 1);
+
+  psf = psf->next;
+}
+
+  fprintf (asm_out_file, "\t.balign\t4\n");
+  fprintf (asm_out_file, ".Lstrtableend:\n");
+
+  write_file_checksums ();
+
   while (funcs)
 {
   struct pdb_func *n = funcs->next;
@@ -993,6 +1056,134 @@ find_type (tree t)
 return NULL;
 }
 
+#ifndef _WIN32
+/* Given a Unix-style path, construct a fake Windows path, which is what windbg
+ * and Visual Studio are expecting. This maps / to Z:\, which is the default
+ * behaviour on Wine. */
+static char *
+make_windows_path (char *src)
+{
+  size_t len = strlen (src);
+  cha

[PATCH 04/24] pdbout: Output details of variables within functions.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 1272 +-
 gcc/pdbout.h |  969 ++
 2 files changed, 2238 insertions(+), 3 deletions(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index 17011134d7a..2f5b52b6fc3 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -32,6 +32,12 @@
 #include "function.h"
 #include "output.h"
 #include "target.h"
+#include "rtl.h"
+#include "insn-config.h"
+#include "reload.h"
+#include "cp/cp-tree.h"
+#include "common/common-target.h"
+#include "except.h"
 
 #define FUNC_BEGIN_LABEL   ".Lstartfunc"
 #define FUNC_END_LABEL ".Lendfunc"
@@ -44,10 +50,16 @@ static void pdbout_end_epilogue (unsigned int line 
ATTRIBUTE_UNUSED,
 static void pdbout_finish (const char *filename);
 static void pdbout_begin_function (tree func);
 static void pdbout_late_global_decl (tree var);
+static void pdbout_function_decl (tree decl);
+static void pdbout_begin_block (unsigned int line ATTRIBUTE_UNUSED,
+   unsigned int blocknum);
+static void pdbout_end_block (unsigned int line ATTRIBUTE_UNUSED,
+ unsigned int blocknum);
 
 static struct pdb_type *find_type (tree t);
 
 static struct pdb_func *funcs = NULL, *cur_func = NULL;
+static struct pdb_block *cur_block = NULL;
 static struct pdb_global_var *global_vars = NULL;
 static struct pdb_type *types = NULL, *last_type = NULL;
 static hash_table  tree_hash_table (31);
@@ -73,8 +85,8 @@ const struct gcc_debug_hooks pdb_debug_hooks = {
   debug_nothing_int_charstar,  /* undef */
   debug_nothing_int_charstar,  /* start_source_file */
   debug_nothing_int,   /* end_source_file */
-  debug_nothing_int_int,   /* begin_block */
-  debug_nothing_int_int,   /* end_block */
+  pdbout_begin_block,
+  pdbout_end_block,
   debug_true_const_tree,   /* ignore_block */
   debug_nothing_int_int_charstar_int_bool, /* source_line */
   pdbout_begin_prologue,
@@ -84,7 +96,7 @@ const struct gcc_debug_hooks pdb_debug_hooks = {
   pdbout_begin_function,
   debug_nothing_int,   /* end_function */
   debug_nothing_tree,  /* register_main_translation_unit */
-  debug_nothing_tree,  /* function_decl */
+  pdbout_function_decl,
   debug_nothing_tree,  /* early_global_decl */
   pdbout_late_global_decl,
   debug_nothing_tree_int,  /* type_decl */
@@ -122,6 +134,198 @@ pdbout_end_epilogue (unsigned int line ATTRIBUTE_UNUSED,
   fprintf (asm_out_file, FUNC_END_LABEL "%u:\n", current_function_funcdef_no);
 }
 
+/* Output the information as to where to a local variable can be found. */
+static void
+pdbout_local_variable (struct pdb_local_var *v)
+{
+  uint16_t len, align;
+  size_t name_len = strlen (v->name);
+
+  switch (v->var_type)
+{
+case pdb_local_var_regrel:
+  if (v->reg == CV_X86_EBP) // ebp is a special case
+   {
+ len = 13 + name_len;
+
+ if (len % 4 != 0)
+   {
+ align = 4 - (len % 4);
+ len += 4 - (len % 4);
+   }
+ else
+   align = 0;
+
+ /* Output BPRELSYM32 struct */
+
+ fprintf (asm_out_file, "\t.short\t0x%x\n",
+  (uint16_t) (len - sizeof (uint16_t)));   // reclen
+ fprintf (asm_out_file, "\t.short\t0x%x\n", S_BPREL32);
+ fprintf (asm_out_file, "\t.long\t0x%x\n", v->offset);
+ fprintf (asm_out_file, "\t.long\t0x%x\n",
+  v->type ? v->type->id : 0);
+
+ ASM_OUTPUT_ASCII (asm_out_file, v->name, name_len + 1);
+   }
+  else
+   {
+ len = 15 + name_len;
+
+ if (len % 4 != 0)
+   {
+ align = 4 - (len % 4);
+ len += 4 - (len % 4);
+   }
+ else
+   align = 0;
+
+ /* Output REGREL32 struct */
+
+ fprintf (asm_out_file, "\t.short\t0x%x\n",
+  (uint16_t) (len - sizeof (uint16_t)));   // reclen
+ fprintf (asm_out_file, "\t.short\t0x%x\n", S_REGREL32);
+ fprintf (asm_out_file, "\t.long\t0x%x\n", v->offset);
+ fprintf (asm_out_file, "\t.long\t0x%x\n",
+  v->type ? v->type->id : 0);
+ fprintf (asm_out_file, "\t.short\t0x%x\n", v->reg);
+
+ ASM_OUTPUT_ASCII (asm_out_file, v->name, name_len + 1);
+   }
+
+  for (unsigned int i = 0; i < align; i++)
+   {
+ fprintf (asm_out_file, "\t.byte\t0\n");
+   }
+  break;
+
+case pdb_local_var_register:
+  len = 11 + name_len;
+
+  if (len % 4 != 0)
+   {
+ align = 4 - (len % 4);
+ len += 4 - (len % 4);
+   }
+  else
+   align = 0;
+
+  /* Output REGSYM struct */
+
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+  (uint16_t) (len - sizeof (uint16_t)));   // reclen
+  fprintf (asm_out_file, "\t.short\t0x%x\n", S_REGISTER);
+  fprintf (asm_out_file, "\t.long\t0x%x\n",
+  v->type ? v->type->id : 0);
+  fprintf (asm_

[PATCH 08/24] pdbout: Output function prototypes.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 338 ++-
 gcc/pdbout.h |  23 
 2 files changed, 359 insertions(+), 2 deletions(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index 040ac6fe8e4..64f7c1d71bc 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -32,6 +32,7 @@
 #include "function.h"
 #include "output.h"
 #include "target.h"
+#include "config/i386/i386-protos.h"
 #include "md5.h"
 #include "rtl.h"
 #include "insn-config.h"
@@ -43,6 +44,8 @@
 #define FUNC_BEGIN_LABEL   ".Lstartfunc"
 #define FUNC_END_LABEL ".Lendfunc"
 
+#define FIRST_TYPE_NUM 0x1000
+
 static void pdbout_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
   unsigned int column ATTRIBUTE_UNUSED,
   const char *file ATTRIBUTE_UNUSED);
@@ -72,6 +75,8 @@ static struct pdb_func *funcs = NULL, *cur_func = NULL;
 static struct pdb_block *cur_block = NULL;
 static struct pdb_global_var *global_vars = NULL;
 static struct pdb_type *types = NULL, *last_type = NULL;
+static struct pdb_type *arglist_types = NULL;
+static struct pdb_type *proc_types = NULL;
 static struct pdb_source_file *source_files = NULL, *last_source_file = NULL;
 static uint32_t source_file_string_offset = 1;
 static unsigned int num_line_number_entries = 0;
@@ -791,12 +796,142 @@ write_pdb_section (void)
 }
 }
 
-/* We've finished compilation - output the .debug$S section
+/* Free a pdb_type that we've allocated. */
+static void
+free_type (struct pdb_type *t)
+{
+  free (t);
+}
+
+/* Output a lfArgList structure, describing the arguments that a
+ * procedure expects. */
+static void
+write_arglist (struct pdb_arglist *arglist)
+{
+  unsigned int len = 8 + (4 * arglist->count);
+
+  if (arglist->count == 0) // zero-length arglist has dummy entry
+len += 4;
+
+  fprintf (asm_out_file, "\t.short\t0x%x\n", len - 2);
+  fprintf (asm_out_file, "\t.short\t0x%x\n", LF_ARGLIST);
+  fprintf (asm_out_file, "\t.long\t0x%x\n",
+  arglist->count == 0 ? 1 : arglist->count);
+
+  for (unsigned int i = 0; i < arglist->count; i++)
+{
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+  arglist->args[i] ? arglist->args[i]->id : 0);
+  fprintf (asm_out_file, "\t.short\t0\n"); // padding
+}
+
+  if (arglist->count == 0)
+{
+  fprintf (asm_out_file, "\t.short\t0\n"); // empty type
+  fprintf (asm_out_file, "\t.short\t0\n"); // padding
+}
+}
+
+/* Output a lfProc structure, which describes the prototype of a
+ * procedure. See also pdbout_proc32, which outputs the details of
+ * a specific procedure. */
+static void
+write_procedure (struct pdb_proc *proc)
+{
+  fprintf (asm_out_file, "\t.short\t0xe\n");
+  fprintf (asm_out_file, "\t.short\t0x%x\n", LF_PROCEDURE);
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+  proc->return_type ? proc->return_type->id : 0);
+  fprintf (asm_out_file, "\t.short\t0\n"); // padding
+  fprintf (asm_out_file, "\t.byte\t0x%x\n", proc->calling_convention);
+  fprintf (asm_out_file, "\t.byte\t0x%x\n", proc->attributes);
+  fprintf (asm_out_file, "\t.short\t0x%x\n", proc->num_args);
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+  proc->arg_list ? proc->arg_list->id : 0);
+  fprintf (asm_out_file, "\t.short\t0\n"); // padding
+}
+
+/* Given a pdb_type, output its definition. */
+static void
+write_type (struct pdb_type *t)
+{
+  switch (t->cv_type)
+{
+case LF_ARGLIST:
+  write_arglist ((struct pdb_arglist *) t->data);
+  break;
+
+case LF_PROCEDURE:
+  write_procedure ((struct pdb_proc *) t->data);
+  break;
+}
+}
+
+/* Output the .debug$T section, which contains all the types used. */
+static void
+write_pdb_type_section (void)
+{
+  struct pdb_type *n;
+
+  fprintf (asm_out_file, "\t.section\t.debug$T, \"ndr\"\n");
+  fprintf (asm_out_file, "\t.long\t0x%x\n", CV_SIGNATURE_C13);
+
+  n = types;
+  while (n)
+{
+  write_type (n);
+
+  n = n->next;
+}
+
+  while (types)
+{
+  n = types->next;
+
+  free_type (types);
+
+  types = n;
+}
+}
+
+/* Loop through our types and assign them sequential numbers. */
+static void
+number_types (void)
+{
+  struct pdb_type *t;
+  uint16_t type_num = FIRST_TYPE_NUM;
+
+  t = types;
+  while (t)
+{
+  if (t->id != 0)
+   {
+ t = t->next;
+ continue;
+   }
+
+  t->id = type_num;
+  type_num++;
+
+  if (type_num == 0)   // overflow
+   {
+ fprintf (stderr, "too many CodeView types\n");
+ xexit (1);
+   }
+
+  t = t->next;
+}
+}
+
+/* We've finished compilation - output the .debug$S and .debug$T sections
  * to the asm file. */
 static void
 pdbout_finish (const char *filename ATTRIBUTE_UNUSED)
 {
+  number_types ();
+
   write_pdb_section ();
+  write_pdb_type_section ();
 }
 
 /* For a tree t, construct the name. */
@@ -877,6 +1012,197 @@ pdbout_late_global_decl (tree var)
   global_vars = v;
 }
 
+/* Ad

[PATCH 09/24] pdbout: Output information about pointers.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 131 ---
 gcc/pdbout.h |  36 ++
 2 files changed, 161 insertions(+), 6 deletions(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index 64f7c1d71bc..08bb14364e5 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -76,6 +76,7 @@ static struct pdb_block *cur_block = NULL;
 static struct pdb_global_var *global_vars = NULL;
 static struct pdb_type *types = NULL, *last_type = NULL;
 static struct pdb_type *arglist_types = NULL;
+static struct pdb_type *pointer_types = NULL;
 static struct pdb_type *proc_types = NULL;
 static struct pdb_source_file *source_files = NULL, *last_source_file = NULL;
 static uint32_t source_file_string_offset = 1;
@@ -803,6 +804,17 @@ free_type (struct pdb_type *t)
   free (t);
 }
 
+/* Output a lfPointer structure. */
+static void
+write_pointer (struct pdb_pointer *ptr)
+{
+  fprintf (asm_out_file, "\t.short\t0xa\n");
+  fprintf (asm_out_file, "\t.short\t0x%x\n", LF_POINTER);
+  fprintf (asm_out_file, "\t.short\t0x%x\n", ptr->type ? ptr->type->id : 0);
+  fprintf (asm_out_file, "\t.short\t0\n"); // padding
+  fprintf (asm_out_file, "\t.long\t0x%x\n", ptr->attr.num);
+}
+
 /* Output a lfArgList structure, describing the arguments that a
  * procedure expects. */
 static void
@@ -857,6 +869,13 @@ write_type (struct pdb_type *t)
 {
   switch (t->cv_type)
 {
+case LF_POINTER:
+  if (t->id < FIRST_TYPE_NUM)  // pointer to builtin
+   return;
+
+  write_pointer ((struct pdb_pointer *) t->data);
+  break;
+
 case LF_ARGLIST:
   write_arglist ((struct pdb_arglist *) t->data);
   break;
@@ -910,13 +929,38 @@ number_types (void)
  continue;
}
 
-  t->id = type_num;
-  type_num++;
-
-  if (type_num == 0)   // overflow
+  switch (t->cv_type)
{
- fprintf (stderr, "too many CodeView types\n");
- xexit (1);
+   case LF_POINTER:
+ {
+   struct pdb_pointer *ptr = (struct pdb_pointer *) t->data;
+
+   // pointers to builtins have their own constants
+   if (ptr->type && ptr->type->id != 0 && ptr->type->id < 0x100)
+ {
+   if (ptr->attr.s.ptrtype == CV_PTR_NEAR32)
+ {
+   t->id = (CV_TM_NPTR32 << 8) | ptr->type->id;
+   break;
+ }
+   else if (ptr->attr.s.ptrtype == CV_PTR_64)
+ {
+   t->id = (CV_TM_NPTR64 << 8) | ptr->type->id;
+   break;
+ }
+ }
+   [[fallthrough]];
+ }
+
+   default:
+ t->id = type_num;
+ type_num++;
+
+ if (type_num == 0)// overflow
+   {
+ fprintf (stderr, "too many CodeView types\n");
+ xexit (1);
+   }
}
 
   t = t->next;
@@ -1072,6 +1116,77 @@ add_arglist_type (struct pdb_type *t)
   return t;
 }
 
+/* Given a pointer type t, allocate a new pdb_type and add it to the
+ * type list. */
+static struct pdb_type *
+find_type_pointer (tree t)
+{
+  struct pdb_type *ptrtype, *t2, *last_entry = NULL, *type;
+  struct pdb_pointer *ptr, v;
+  unsigned int size = TREE_INT_CST_ELT (TYPE_SIZE (t), 0) / 8;
+  struct pdb_type **slot;
+
+  type = find_type (TREE_TYPE (t));
+
+  if (!type)
+return NULL;
+
+  v.attr.num = 0;
+
+  v.attr.s.size = size;
+
+  if (size == 8)
+v.attr.s.ptrtype = CV_PTR_64;
+  else if (size == 4)
+v.attr.s.ptrtype = CV_PTR_NEAR32;
+
+  if (TREE_CODE (t) == REFERENCE_TYPE)
+v.attr.s.ptrmode =
+  TYPE_REF_IS_RVALUE (t) ? CV_PTR_MODE_RVREF : CV_PTR_MODE_LVREF;
+
+  t2 = pointer_types;
+  while (t2)
+{
+  ptr = (struct pdb_pointer *) t2->data;
+
+  if (ptr->type == type && ptr->attr.num == v.attr.num)
+   return t2;
+
+  last_entry = t2;
+  t2 = t2->next2;
+}
+
+  ptrtype =
+(struct pdb_type *) xmalloc (offsetof (struct pdb_type, data) +
+sizeof (struct pdb_pointer));
+  ptrtype->cv_type = LF_POINTER;
+  ptrtype->tree = t;
+  ptrtype->next = ptrtype->next2 = NULL;
+  ptrtype->id = 0;
+
+  ptr = (struct pdb_pointer *) ptrtype->data;
+  ptr->type = type;
+  ptr->attr.num = v.attr.num;
+
+  if (last_entry)
+last_entry->next2 = ptrtype;
+  else
+pointer_types = ptrtype;
+
+  if (last_type)
+last_type->next = ptrtype;
+  else
+types = ptrtype;
+
+  last_type = ptrtype;
+
+  slot =
+tree_hash_table.find_slot_with_hash (t, htab_hash_pointer (t), INSERT);
+  *slot = ptrtype;
+
+  return ptrtype;
+}
+
 /* Given a function type t, allocate a new pdb_type and add it to the
  * type list. */
 static struct pdb_type *
@@ -1478,6 +1593,10 @@ find_type (tree t)
 
   switch (TREE_CODE (t))
 {
+case POINTER_TYPE:
+case REFERENCE_TYPE:
+  return find_type_pointer (t);
+
 case FUNCTION_TYPE:
 case METHOD_TYPE:
   return find_type_function (t);
diff --git a/gcc/pdbout.h b/gcc/pdbou

[PATCH 10/24] pdbout: Output information about CV type modifiers.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 85 
 gcc/pdbout.h | 11 +++
 2 files changed, 96 insertions(+)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index 08bb14364e5..fa3b1fb0312 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -78,6 +78,7 @@ static struct pdb_type *types = NULL, *last_type = NULL;
 static struct pdb_type *arglist_types = NULL;
 static struct pdb_type *pointer_types = NULL;
 static struct pdb_type *proc_types = NULL;
+static struct pdb_type *modifier_types = NULL;
 static struct pdb_source_file *source_files = NULL, *last_source_file = NULL;
 static uint32_t source_file_string_offset = 1;
 static unsigned int num_line_number_entries = 0;
@@ -863,6 +864,19 @@ write_procedure (struct pdb_proc *proc)
   fprintf (asm_out_file, "\t.short\t0\n"); // padding
 }
 
+/* Output lfModifier structure, representing a const or volatile version
+ * of an existing type. */
+static void
+write_modifier (struct pdb_modifier *t)
+{
+  fprintf (asm_out_file, "\t.short\t0xa\n");
+  fprintf (asm_out_file, "\t.short\t0x%x\n", LF_MODIFIER);
+  fprintf (asm_out_file, "\t.short\t0x%x\n", t->type ? t->type->id : 0);
+  fprintf (asm_out_file, "\t.short\t0\n"); // padding
+  fprintf (asm_out_file, "\t.short\t0x%x\n", t->modifier);
+  fprintf (asm_out_file, "\t.short\t0\n"); // padding
+}
+
 /* Given a pdb_type, output its definition. */
 static void
 write_type (struct pdb_type *t)
@@ -883,6 +897,10 @@ write_type (struct pdb_type *t)
 case LF_PROCEDURE:
   write_procedure ((struct pdb_proc *) t->data);
   break;
+
+case LF_MODIFIER:
+  write_modifier ((struct pdb_modifier *) t->data);
+  break;
 }
 }
 
@@ -1318,6 +1336,68 @@ find_type_function (tree t)
   return proctype;
 }
 
+/* Given a CV-modified type t, allocate a new pdb_type modifying
+ * the base type, and add it to the type list. */
+static struct pdb_type *
+find_type_modifier (tree t)
+{
+  struct pdb_type *type, *last_entry = NULL, *base_type;
+  struct pdb_modifier *mod;
+  uint16_t modifier = 0;
+  struct pdb_type **slot;
+
+  base_type = find_type (TYPE_MAIN_VARIANT (t));
+
+  if (TYPE_READONLY (t))
+modifier |= CV_MODIFIER_CONST;
+
+  if (TYPE_VOLATILE (t))
+modifier |= CV_MODIFIER_VOLATILE;
+
+  type = modifier_types;
+  while (type)
+{
+  mod = (struct pdb_modifier *) type->data;
+
+  if (mod->type == base_type && mod->modifier == modifier)
+   return type;
+
+  last_entry = type;
+  type = type->next2;
+}
+
+  type =
+(struct pdb_type *) xmalloc (offsetof (struct pdb_type, data) +
+sizeof (struct pdb_modifier));
+  type->cv_type = LF_MODIFIER;
+  type->tree = t;
+  type->next = type->next2 = NULL;
+  type->id = 0;
+
+  mod = (struct pdb_modifier *) type->data;
+
+  mod->type = base_type;
+  mod->modifier = modifier;
+
+  if (last_entry)
+last_entry->next2 = type;
+  else
+modifier_types = type;
+
+  if (last_type)
+last_type->next = type;
+  else
+types = type;
+
+  last_type = type;
+
+  slot =
+tree_hash_table.find_slot_with_hash (t, htab_hash_pointer (t), INSERT);
+  *slot = type;
+
+  return type;
+}
+
 inline hashval_t
 pdb_type_tree_hasher::hash (pdb_type_tree_hasher::compare_type tree)
 {
@@ -1439,6 +1519,11 @@ find_type (tree t)
   if (type)
 return type;
 
+  // add modifier type if const or volatile
+
+  if (TYPE_READONLY (t) || TYPE_VOLATILE (t))
+return find_type_modifier (t);
+
   switch (TREE_CODE (t))
 {
 case INTEGER_TYPE:
diff --git a/gcc/pdbout.h b/gcc/pdbout.h
index a660728158e..1fa2b1ab2fa 100644
--- a/gcc/pdbout.h
+++ b/gcc/pdbout.h
@@ -21,6 +21,7 @@
 #define GCC_PDBOUT_H 1
 
 #define S_END  0x0006
+#define LF_MODIFIER0x1001
 #define LF_POINTER 0x1002
 #define LF_PROCEDURE   0x1008
 #define S_BLOCK32  0x1103
@@ -262,6 +263,16 @@ struct pdb_source_file
   char name[1];
 };
 
+#define CV_MODIFIER_CONST  0x1
+#define CV_MODIFIER_VOLATILE   0x2
+#define CV_MODIFIER_UNALIGNED  0x4
+
+struct pdb_modifier
+{
+  struct pdb_type *type;
+  uint16_t modifier;
+};
+
 enum pdb_x86_register
 {
   CV_X86_NONE = 0,
-- 
2.26.2



[PATCH 12/24] pdbout: Handle type declarations and typedefs.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 76 +++-
 gcc/pdbout.h | 22 +++
 2 files changed, 97 insertions(+), 1 deletion(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index 8376b0e762c..5089203e339 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -55,6 +55,7 @@ static void pdbout_init (const char *filename);
 static void pdbout_finish (const char *filename);
 static void pdbout_begin_function (tree func);
 static void pdbout_late_global_decl (tree var);
+static void pdbout_type_decl (tree t, int local ATTRIBUTE_UNUSED);
 static void pdbout_start_source_file (unsigned int line ATTRIBUTE_UNUSED,
  const char *file);
 static void pdbout_source_line (unsigned int line,
@@ -80,6 +81,7 @@ static struct pdb_type *pointer_types = NULL;
 static struct pdb_type *proc_types = NULL;
 static struct pdb_type *modifier_types = NULL;
 static struct pdb_type *array_types = NULL;
+static struct pdb_alias *aliases = NULL;
 static struct pdb_source_file *source_files = NULL, *last_source_file = NULL;
 static uint32_t source_file_string_offset = 1;
 static unsigned int num_line_number_entries = 0;
@@ -98,6 +100,7 @@ static struct pdb_type *complex16_type, *complex32_type, 
*complex48_type,
   *complex64_type, *complex80_type, *complex128_type;
 static struct pdb_type *void_type, *nullptr_type;
 static bool builtins_initialized = false;
+static hash_table  alias_hash_table (31);
 
 const struct gcc_debug_hooks pdb_debug_hooks = {
   pdbout_init,
@@ -122,7 +125,7 @@ const struct gcc_debug_hooks pdb_debug_hooks = {
   pdbout_function_decl,
   debug_nothing_tree,  /* early_global_decl */
   pdbout_late_global_decl,
-  debug_nothing_tree_int,  /* type_decl */
+  pdbout_type_decl,
   debug_nothing_tree_tree_tree_bool_bool,  /* imported_module_or_decl */
   debug_false_tree_charstarstar_uhwistar,  /* die_ref_for_decl */
   debug_nothing_tree_charstar_uhwi,/* register_external_die */
@@ -999,6 +1002,17 @@ write_pdb_type_section (void)
 
   types = n;
 }
+
+  while (aliases)
+{
+  struct pdb_alias *n;
+
+  n = aliases->next;
+
+  free (aliases);
+
+  aliases = n;
+}
 }
 
 /* Loop through our types and assign them sequential numbers. */
@@ -1635,6 +1649,7 @@ static struct pdb_type *
 find_type (tree t)
 {
   struct pdb_type *type;
+  struct pdb_alias *al;
 
   if (!builtins_initialized)
 add_builtin_types ();
@@ -1642,6 +1657,13 @@ find_type (tree t)
   if (!t)
 return NULL;
 
+  // search through typedefs
+
+  al = alias_hash_table.find_with_hash (t, alias_hasher::hash (t));
+
+  if (al)
+return al->type;
+
   // search through existing types
 
   type = tree_hash_table.find_with_hash (t, pdb_type_tree_hasher::hash (t));
@@ -1824,6 +1846,58 @@ find_type (tree t)
 }
 }
 
+inline hashval_t
+alias_hasher::hash (alias_hasher::compare_type tree)
+{
+  return htab_hash_pointer (tree);
+}
+
+inline bool
+alias_hasher::equal (const value_type type, compare_type tree)
+{
+  return type->tree == tree;
+}
+
+/* We've encountered a type definition - add it to the type list. */
+static void
+pdbout_type_decl (tree t, int local ATTRIBUTE_UNUSED)
+{
+  /* We need to record the typedefs to ensure e.g. that Windows'
+   * LPWSTR gets mapped to wchar_t* rather than uint16_t*.
+   * There is a LF_ALIAS / lfAlias in Microsoft's header files, but
+   * it seems to have been forgotten about - MSVC won't generate it. */
+
+  if (DECL_ORIGINAL_TYPE (t))  // typedef
+{
+  struct pdb_alias *a, **slot;
+
+  a = (struct pdb_alias *) xmalloc (sizeof (struct pdb_alias));
+
+  a->next = aliases;
+  a->tree = TREE_TYPE (t);
+  a->type = find_type (DECL_ORIGINAL_TYPE (t));
+
+  // HRESULTs have their own value
+  if (a->type == long_type && DECL_NAME (t)
+ && IDENTIFIER_POINTER (DECL_NAME (t))
+ && !strcmp (IDENTIFIER_POINTER (DECL_NAME (t)), "HRESULT"))
+   a->type = hresult_type;
+
+  slot =
+   alias_hash_table.find_slot_with_hash (TREE_TYPE (t),
+ htab_hash_pointer (TREE_TYPE
+(t)),
+ INSERT);
+  *slot = a;
+
+  aliases = a;
+
+  return;
+}
+
+  find_type (TREE_TYPE (t));
+}
+
 #ifndef _WIN32
 /* Given a Unix-style path, construct a fake Windows path, which is what windbg
  * and Visual Studio are expecting. This maps / to Z:\, which is the default
diff --git a/gcc/pdbout.h b/gcc/pdbout.h
index 412378a63ac..3e5ef8ca1a7 100644
--- a/gcc/pdbout.h
+++ b/gcc/pdbout.h
@@ -201,6 +201,13 @@ struct pdb_type
   uint8_t data[1];
 };
 
+struct pdb_alias
+{
+  struct pdb_alias *next;
+  tree_node *tree;
+  struct pdb_type *type;
+};
+
 #define CV_BUILTIN_TYPE_VOID   0x0003
 #define CV_BUILTIN_TYPE_HRESULT0x0008
 #define CV_BUILTIN_TYPE_SIGNED_CHARACTER   0x0010
@@ -122

[PATCH 11/24] pdbout: Output array types.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 133 +++
 gcc/pdbout.h |  15 ++
 2 files changed, 148 insertions(+)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index fa3b1fb0312..8376b0e762c 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -79,6 +79,7 @@ static struct pdb_type *arglist_types = NULL;
 static struct pdb_type *pointer_types = NULL;
 static struct pdb_type *proc_types = NULL;
 static struct pdb_type *modifier_types = NULL;
+static struct pdb_type *array_types = NULL;
 static struct pdb_source_file *source_files = NULL, *last_source_file = NULL;
 static uint32_t source_file_string_offset = 1;
 static unsigned int num_line_number_entries = 0;
@@ -816,6 +817,71 @@ write_pointer (struct pdb_pointer *ptr)
   fprintf (asm_out_file, "\t.long\t0x%x\n", ptr->attr.num);
 }
 
+/* Output a lfArray structure. */
+static void
+write_array (struct pdb_array *arr)
+{
+  uint16_t len = 15, align;
+
+  if (arr->length >= 0x8000)
+{
+  if (arr->length <= 0x)
+   len += 2;   // LF_USHORT
+  else if (arr->length <= 0x)
+   len += 4;   // LF_ULONG
+  else
+   len += 8;   // LF_UQUADWORD
+}
+
+  align = 4 - (len % 4);
+
+  if (align != 4)
+len += align;
+
+  fprintf (asm_out_file, "\t.short\t0x%lx\n", len - sizeof (uint16_t));
+  fprintf (asm_out_file, "\t.short\t0x%x\n", LF_ARRAY);
+
+  fprintf (asm_out_file, "\t.short\t0x%x\n", arr->type ? arr->type->id : 0);
+  fprintf (asm_out_file, "\t.short\t0\n"); // padding
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+  arr->index_type ? arr->index_type->id : 0);
+  fprintf (asm_out_file, "\t.short\t0\n"); // padding
+
+  if (arr->length >= 0x8000)
+{
+  if (arr->length <= 0x)
+   {
+ fprintf (asm_out_file, "\t.short\t0x%x\n", LF_USHORT);
+ fprintf (asm_out_file, "\t.short\t0x%x\n", (uint16_t) arr->length);
+   }
+  else if (arr->length <= 0x)
+   {
+ fprintf (asm_out_file, "\t.short\t0x%x\n", LF_ULONG);
+ fprintf (asm_out_file, "\t.long\t0x%x\n", (uint32_t) arr->length);
+   }
+  else
+   {
+ fprintf (asm_out_file, "\t.short\t0x%x\n", LF_UQUADWORD);
+ fprintf (asm_out_file, "\t.quad\t0x%" PRIx64 "\n", arr->length);
+   }
+}
+  else
+fprintf (asm_out_file, "\t.short\t0x%x\n", (uint32_t) arr->length);
+
+  fprintf (asm_out_file, "\t.byte\t0\n");  // empty string
+
+  if (align != 4)
+{
+  if (align == 3)
+   fprintf (asm_out_file, "\t.byte\t0xf3\n");
+
+  if (align >= 2)
+   fprintf (asm_out_file, "\t.byte\t0xf2\n");
+
+  fprintf (asm_out_file, "\t.byte\t0xf1\n");
+}
+}
+
 /* Output a lfArgList structure, describing the arguments that a
  * procedure expects. */
 static void
@@ -890,6 +956,10 @@ write_type (struct pdb_type *t)
   write_pointer ((struct pdb_pointer *) t->data);
   break;
 
+case LF_ARRAY:
+  write_array ((struct pdb_array *) t->data);
+  break;
+
 case LF_ARGLIST:
   write_arglist ((struct pdb_arglist *) t->data);
   break;
@@ -1074,6 +1144,66 @@ pdbout_late_global_decl (tree var)
   global_vars = v;
 }
 
+/* Given an array type t, allocate a new pdb_type and add it to the
+ * type list. */
+static struct pdb_type *
+find_type_array (tree t)
+{
+  struct pdb_type *arrtype, *last_entry = NULL, *type;
+  struct pdb_array *arr;
+  uint64_t length =
+TYPE_SIZE (t) ? (TREE_INT_CST_ELT (TYPE_SIZE (t), 0) / 8) : 0;
+  struct pdb_type **slot;
+
+  type = find_type (TREE_TYPE (t));
+
+  if (!type)
+return NULL;
+
+  arrtype = array_types;
+  while (arrtype)
+{
+  arr = (struct pdb_array *) arrtype->data;
+
+  if (arr->type == type && arr->length == length)
+   return arrtype;
+
+  last_entry = arrtype;
+  arrtype = arrtype->next2;
+}
+
+  arrtype =
+(struct pdb_type *) xmalloc (offsetof (struct pdb_type, data) +
+sizeof (struct pdb_array));
+  arrtype->cv_type = LF_ARRAY;
+  arrtype->tree = t;
+  arrtype->next = arrtype->next2 = NULL;
+  arrtype->id = 0;
+
+  arr = (struct pdb_array *) arrtype->data;
+  arr->type = type;
+  arr->index_type = ulong_type;
+  arr->length = length;
+
+  if (last_entry)
+last_entry->next2 = arrtype;
+  else
+array_types = arrtype;
+
+  if (last_type)
+last_type->next = arrtype;
+  else
+types = arrtype;
+
+  last_type = arrtype;
+
+  slot =
+tree_hash_table.find_slot_with_hash (t, htab_hash_pointer (t), INSERT);
+  *slot = arrtype;
+
+  return arrtype;
+}
+
 /* Add an argument list type. */
 static pdb_type *
 add_arglist_type (struct pdb_type *t)
@@ -1682,6 +1812,9 @@ find_type (tree t)
 case REFERENCE_TYPE:
   return find_type_pointer (t);
 
+case ARRAY_TYPE:
+  return find_type_array (t);
+
 case FUNCTION_TYPE:
 case METHOD_TYPE:
   return find_type_function (t);
diff --git a/gcc/pdbout.h b/gcc/pdbout.h
index 1fa2b1ab2fa..412378a63

[PATCH 13/24] pdbout: Output information about enums.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 449 +++
 gcc/pdbout.h |  43 +
 2 files changed, 492 insertions(+)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index 5089203e339..9701aaf8902 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -46,6 +46,8 @@
 
 #define FIRST_TYPE_NUM 0x1000
 
+static const char unnamed[] = "";
+
 static void pdbout_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
   unsigned int column ATTRIBUTE_UNUSED,
   const char *file ATTRIBUTE_UNUSED);
@@ -80,6 +82,8 @@ static struct pdb_type *arglist_types = NULL;
 static struct pdb_type *pointer_types = NULL;
 static struct pdb_type *proc_types = NULL;
 static struct pdb_type *modifier_types = NULL;
+static struct pdb_type *fieldlist_types = NULL;
+static struct pdb_type *enum_types = NULL;
 static struct pdb_type *array_types = NULL;
 static struct pdb_alias *aliases = NULL;
 static struct pdb_source_file *source_files = NULL, *last_source_file = NULL;
@@ -806,9 +810,235 @@ write_pdb_section (void)
 static void
 free_type (struct pdb_type *t)
 {
+  switch (t->cv_type)
+{
+case LF_FIELDLIST:
+  {
+   struct pdb_fieldlist *fl = (struct pdb_fieldlist *) t->data;
+
+   for (unsigned int i = 0; i < fl->count; i++)
+ {
+   if (fl->entries[i].name)
+ free (fl->entries[i].name);
+ }
+
+   break;
+  }
+
+case LF_ENUM:
+  {
+   struct pdb_enum *en = (struct pdb_enum *) t->data;
+
+   if (en->name)
+ free (en->name);
+
+   break;
+  }
+}
+
   free (t);
 }
 
+/* Output a lfFieldlist structure, which describes the values of an enum. */
+static void
+write_fieldlist (struct pdb_fieldlist *fl)
+{
+  unsigned int len = 4;
+
+  for (unsigned int i = 0; i < fl->count; i++)
+{
+  len += 2;
+
+  switch (fl->entries[i].cv_type)
+   {
+   case LF_ENUMERATE:
+ len += 5;
+
+ /* Positive values less than 0x8000 are stored as they are; otherwise
+  * we prepend two bytes describing what type it is. */
+
+ if (fl->entries[i].value >= 0x8000 || fl->entries[i].value < 0)
+   {
+ if (fl->entries[i].value >= -127 && fl->entries[i].value < 0)
+   len++;  // LF_CHAR
+ else if (fl->entries[i].value >= -0x7fff &&
+  fl->entries[i].value <= 0x7fff)
+   {
+ len += 2; // LF_SHORT
+   }
+ else if (fl->entries[i].value >= 0x8000 &&
+  fl->entries[i].value <= 0x)
+   {
+ len += 2; // LF_USHORT
+   }
+ else if (fl->entries[i].value >= -0x7fff &&
+  fl->entries[i].value <= 0x7fff)
+   {
+ len += 4; // LF_LONG
+   }
+ else if (fl->entries[i].value >= 0x8000 &&
+  fl->entries[i].value <= 0x)
+   {
+ len += 4; // LF_ULONG
+   }
+ else
+   len += 8;   // LF_QUADWORD or LF_UQUADWORD
+   }
+
+ if (fl->entries[i].name)
+   len += strlen (fl->entries[i].name);
+
+ break;
+   }
+
+  if (len % 4 != 0)
+   len += 4 - (len % 4);
+}
+
+  fprintf (asm_out_file, "\t.short\t0x%x\n", len - 2);
+  fprintf (asm_out_file, "\t.short\t0x%x\n", LF_FIELDLIST);
+
+  for (unsigned int i = 0; i < fl->count; i++)
+{
+  fprintf (asm_out_file, "\t.short\t0x%x\n", fl->entries[i].cv_type);
+
+  switch (fl->entries[i].cv_type)
+   {
+   case LF_ENUMERATE:
+ {
+   size_t name_len =
+ fl->entries[i].name ? strlen (fl->entries[i].name) : 0;
+   unsigned int align;
+
+   fprintf (asm_out_file, "\t.short\t0x%x\n",
+fl->entries[i].fld_attr);
+
+   align = (3 + name_len) % 4;
+
+   if (fl->entries[i].value >= 0 && fl->entries[i].value < 0x8000)
+ fprintf (asm_out_file, "\t.short\t0x%x\n",
+ (uint16_t) fl->entries[i].value);
+   else if (fl->entries[i].value >= -127 && fl->entries[i].value < 0)
+ {
+   fprintf (asm_out_file, "\t.short\t0x%x\n", LF_CHAR);
+   fprintf (asm_out_file, "\t.byte\t0x%x\n",
+   (unsigned int) ((int8_t) fl->entries[i].value & 0xff));
+
+   align = (align + 1) % 4;
+ }
+   else if (fl->entries[i].value >= -0x7fff
+   && fl->entries[i].value <= 0x7fff)
+ {
+   fprintf (asm_out_file, "\t.short\t0x%x\n", LF_SHORT);
+   fprintf (asm_out_file, "\t.short\t0x%x\n",
+   (unsigned int) ((int16_t) fl->entries[i].
+   value & 0x));
+
+   align = (align + 2) % 4;
+ }
+   

[PATCH 15/24] pdbout: Output definitions of unions.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 62 +++-
 gcc/pdbout.h |  1 +
 2 files changed, 57 insertions(+), 6 deletions(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index 3bfec519877..7d493513e06 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -829,6 +829,7 @@ free_type (struct pdb_type *t)
 
 case LF_CLASS:
 case LF_STRUCTURE:
+case LF_UNION:
   {
struct pdb_struct *str = (struct pdb_struct *) t->data;
 
@@ -1097,6 +1098,44 @@ write_struct (uint16_t type, struct pdb_struct *str)
 }
 }
 
+/* Output a lfUnion structure. */
+static void
+write_union (struct pdb_struct *str)
+{
+  size_t name_len = str->name ? strlen (str->name) : (sizeof (unnamed) - 1);
+  unsigned int len = 15 + name_len, align;
+
+  if (len % 4 != 0)
+len += 4 - (len % 4);
+
+  fprintf (asm_out_file, "\t.short\t0x%x\n", len - 2);
+  fprintf (asm_out_file, "\t.short\t0x%x\n", LF_UNION);
+  fprintf (asm_out_file, "\t.short\t0x%x\n", str->count);
+  fprintf (asm_out_file, "\t.short\t0x%x\n", str->property.value);
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+  str->field_type ? str->field_type->id : 0);
+  fprintf (asm_out_file, "\t.short\t0\n");
+  fprintf (asm_out_file, "\t.short\t0x%x\n", str->size);
+
+  if (str->name)
+ASM_OUTPUT_ASCII (asm_out_file, str->name, name_len + 1);
+  else
+ASM_OUTPUT_ASCII (asm_out_file, unnamed, sizeof (unnamed));
+
+  align = 4 - ((3 + name_len) % 4);
+
+  if (align != 4)
+{
+  if (align == 3)
+   fprintf (asm_out_file, "\t.byte\t0xf3\n");
+
+  if (align >= 2)
+   fprintf (asm_out_file, "\t.byte\t0xf2\n");
+
+  fprintf (asm_out_file, "\t.byte\t0xf1\n");
+}
+}
+
 /* Output a lfEnum structure. */
 static void
 write_enum (struct pdb_enum *en)
@@ -1288,6 +1327,10 @@ write_type (struct pdb_type *t)
   write_struct (t->cv_type, (struct pdb_struct *) t->data);
   break;
 
+case LF_UNION:
+  write_union ((struct pdb_struct *) t->data);
+  break;
+
 case LF_ENUM:
   write_enum ((struct pdb_enum *) t->data);
   break;
@@ -1679,10 +1722,10 @@ struct_hasher::equal (const value_type type, 
compare_type name)
   return !strcmp (str->name, name);
 }
 
-/* For a given struct or class, allocate a new pdb_type and
+/* For a given struct, class, or union, allocate a new pdb_type and
  * add it to the type list. */
 static struct pdb_type *
-find_type_struct (tree t)
+find_type_struct (tree t, bool is_union)
 {
   tree f;
   struct pdb_type *fltype = NULL, *strtype, *fwddef = NULL,
@@ -1729,7 +1772,8 @@ find_type_struct (tree t)
 
  if (type
  && (type->cv_type == LF_CLASS
- || type->cv_type == LF_STRUCTURE))
+ || type->cv_type == LF_STRUCTURE
+ || type->cv_type == LF_UNION))
{
  struct pdb_struct *str2 = (struct pdb_struct *) type->data;
 
@@ -1811,7 +1855,8 @@ find_type_struct (tree t)
 
  if (type
  && (type->cv_type == LF_CLASS
- || type->cv_type == LF_STRUCTURE))
+ || type->cv_type == LF_STRUCTURE
+ || type->cv_type == LF_UNION))
{
  struct pdb_struct *str2 =
(struct pdb_struct *) type->data;
@@ -1880,7 +1925,9 @@ find_type_struct (tree t)
 (struct pdb_type *) xmalloc (offsetof (struct pdb_type, data) +
 sizeof (struct pdb_struct));
 
-  if (TYPE_LANG_SPECIFIC (t) && CLASSTYPE_DECLARED_CLASS (t))
+  if (is_union)
+strtype->cv_type = LF_UNION;
+  else if (TYPE_LANG_SPECIFIC (t) && CLASSTYPE_DECLARED_CLASS (t))
 strtype->cv_type = LF_CLASS;
   else
 strtype->cv_type = LF_STRUCTURE;
@@ -2744,7 +2791,10 @@ find_type (tree t)
   return find_type_array (t);
 
 case RECORD_TYPE:
-  return find_type_struct (t);
+  return find_type_struct (t, false);
+
+case UNION_TYPE:
+  return find_type_struct (t, true);
 
 case ENUMERAL_TYPE:
   return find_type_enum (t);
diff --git a/gcc/pdbout.h b/gcc/pdbout.h
index 96288d235ea..09b3914d650 100644
--- a/gcc/pdbout.h
+++ b/gcc/pdbout.h
@@ -41,6 +41,7 @@
 #define LF_ARRAY   0x1503
 #define LF_CLASS   0x1504
 #define LF_STRUCTURE   0x1505
+#define LF_UNION   0x1506
 #define LF_ENUM0x1507
 #define LF_MEMBER  0x150d
 #define LF_CHAR0x8000
-- 
2.26.2



[PATCH 14/24] pdbout: Output definitions of structs and classes.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 469 ++-
 gcc/pdbout.h |  51 ++
 2 files changed, 517 insertions(+), 3 deletions(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index 9701aaf8902..3bfec519877 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -83,6 +83,7 @@ static struct pdb_type *pointer_types = NULL;
 static struct pdb_type *proc_types = NULL;
 static struct pdb_type *modifier_types = NULL;
 static struct pdb_type *fieldlist_types = NULL;
+static struct pdb_type *struct_types = NULL, *last_struct_type = NULL;
 static struct pdb_type *enum_types = NULL;
 static struct pdb_type *array_types = NULL;
 static struct pdb_alias *aliases = NULL;
@@ -105,6 +106,7 @@ static struct pdb_type *complex16_type, *complex32_type, 
*complex48_type,
 static struct pdb_type *void_type, *nullptr_type;
 static bool builtins_initialized = false;
 static hash_table  alias_hash_table (31);
+static hash_table  struct_hash_table (31);
 
 const struct gcc_debug_hooks pdb_debug_hooks = {
   pdbout_init,
@@ -825,6 +827,17 @@ free_type (struct pdb_type *t)
break;
   }
 
+case LF_CLASS:
+case LF_STRUCTURE:
+  {
+   struct pdb_struct *str = (struct pdb_struct *) t->data;
+
+   if (str->name)
+ free (str->name);
+
+   break;
+  }
+
 case LF_ENUM:
   {
struct pdb_enum *en = (struct pdb_enum *) t->data;
@@ -839,7 +852,8 @@ free_type (struct pdb_type *t)
   free (t);
 }
 
-/* Output a lfFieldlist structure, which describes the values of an enum. */
+/* Output a lfFieldlist structure, which describes the fields of a struct,
+ * class, or union, or the values of an enum. */
 static void
 write_fieldlist (struct pdb_fieldlist *fl)
 {
@@ -851,6 +865,10 @@ write_fieldlist (struct pdb_fieldlist *fl)
 
   switch (fl->entries[i].cv_type)
{
+   case LF_MEMBER:
+ len += 9 + (fl->entries[i].name ? strlen (fl->entries[i].name) : 0);
+ break;
+
case LF_ENUMERATE:
  len += 5;
 
@@ -904,6 +922,43 @@ write_fieldlist (struct pdb_fieldlist *fl)
 
   switch (fl->entries[i].cv_type)
{
+   case LF_MEMBER:
+ {
+   size_t name_len =
+ fl->entries[i].name ? strlen (fl->entries[i].name) : 0;
+   unsigned int align;
+
+   fprintf (asm_out_file, "\t.short\t0x%x\n",
+fl->entries[i].fld_attr);
+   fprintf (asm_out_file, "\t.short\t0x%x\n",
+   fl->entries[i].type ? fl->entries[i].type->id : 0);
+   fprintf (asm_out_file, "\t.short\t0\n");// padding
+   fprintf (asm_out_file, "\t.short\t0x%x\n", fl->entries[i].offset);
+
+   if (fl->entries[i].name)
+ ASM_OUTPUT_ASCII (asm_out_file, fl->entries[i].name,
+   name_len + 1);
+   else
+ fprintf (asm_out_file, "\t.byte\t0\n");
+
+   // handle alignment padding
+
+   align = 4 - ((3 + name_len) % 4);
+
+   if (align != 4)
+ {
+   if (align == 3)
+ fprintf (asm_out_file, "\t.byte\t0xf3\n");
+
+   if (align >= 2)
+ fprintf (asm_out_file, "\t.byte\t0xf2\n");
+
+   fprintf (asm_out_file, "\t.byte\t0xf1\n");
+ }
+
+   break;
+ }
+
case LF_ENUMERATE:
  {
size_t name_len =
@@ -1000,6 +1055,48 @@ write_fieldlist (struct pdb_fieldlist *fl)
 }
 }
 
+/* Output a lfClass / lfStructure struct. */
+static void
+write_struct (uint16_t type, struct pdb_struct *str)
+{
+  size_t name_len = str->name ? strlen (str->name) : (sizeof (unnamed) - 1);
+  unsigned int len = 23 + name_len, align;
+
+  if (len % 4 != 0)
+len += 4 - (len % 4);
+
+  fprintf (asm_out_file, "\t.short\t0x%x\n", len - 2);
+  fprintf (asm_out_file, "\t.short\t0x%x\n", type);
+  fprintf (asm_out_file, "\t.short\t0x%x\n", str->count);
+  fprintf (asm_out_file, "\t.short\t0x%x\n", str->property.value);
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+  str->field_type ? str->field_type->id : 0);
+  fprintf (asm_out_file, "\t.short\t0\n"); // derived
+  fprintf (asm_out_file, "\t.short\t0\n"); // vshape
+  fprintf (asm_out_file, "\t.short\t0\n");
+  fprintf (asm_out_file, "\t.short\t0\n");
+  fprintf (asm_out_file, "\t.short\t0\n");
+  fprintf (asm_out_file, "\t.short\t0x%x\n", str->size);
+
+  if (str->name)
+ASM_OUTPUT_ASCII (asm_out_file, str->name, name_len + 1);
+  else
+ASM_OUTPUT_ASCII (asm_out_file, unnamed, sizeof (unnamed));
+
+  align = 4 - ((3 + name_len) % 4);
+
+  if (align != 4)
+{
+  if (align == 3)
+   fprintf (asm_out_file, "\t.byte\t0xf3\n");
+
+  if (align >= 2)
+   fprintf (asm_out_file, "\t.byte\t0xf2\n");
+
+  fprintf (asm_out_file, "\t.byte\t0xf1\n");
+}
+}
+
 /* Output a lfEnum structure. */
 static void
 write_enum (struct pdb_enum *en)
@@ -1186,6 +1283,11 @@ write_type (struct pdb_type *t)
   write_field

[PATCH 16/24] pdbout: Output definitions of bitfields within structs.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 93 ++--
 gcc/pdbout.h |  8 +
 2 files changed, 99 insertions(+), 2 deletions(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index 7d493513e06..d3f251f22d2 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -85,6 +85,7 @@ static struct pdb_type *modifier_types = NULL;
 static struct pdb_type *fieldlist_types = NULL;
 static struct pdb_type *struct_types = NULL, *last_struct_type = NULL;
 static struct pdb_type *enum_types = NULL;
+static struct pdb_type *bitfield_types = NULL;
 static struct pdb_type *array_types = NULL;
 static struct pdb_alias *aliases = NULL;
 static struct pdb_source_file *source_files = NULL, *last_source_file = NULL;
@@ -1312,6 +1313,22 @@ write_modifier (struct pdb_modifier *t)
   fprintf (asm_out_file, "\t.short\t0\n"); // padding
 }
 
+/* Output lfBitfield structure. */
+static void
+write_bitfield (struct pdb_bitfield *t)
+{
+  fprintf (asm_out_file, "\t.short\t0xa\n");
+  fprintf (asm_out_file, "\t.short\t0x%x\n", LF_BITFIELD);
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+  t->underlying_type ? t->underlying_type->id : 0);
+  fprintf (asm_out_file, "\t.short\t0\n"); // padding
+  fprintf (asm_out_file, "\t.byte\t0x%x\n", t->size);
+  fprintf (asm_out_file, "\t.byte\t0x%x\n", t->offset);
+
+  fprintf (asm_out_file, "\t.byte\t0xf2\n");   // alignment
+  fprintf (asm_out_file, "\t.byte\t0xf1\n");   // alignment
+}
+
 /* Given a pdb_type, output its definition. */
 static void
 write_type (struct pdb_type *t)
@@ -1357,6 +1374,10 @@ write_type (struct pdb_type *t)
 case LF_MODIFIER:
   write_modifier ((struct pdb_modifier *) t->data);
   break;
+
+case LF_BITFIELD:
+  write_bitfield ((struct pdb_bitfield *) t->data);
+  break;
 }
 }
 
@@ -1548,6 +1569,57 @@ pdbout_late_global_decl (tree var)
   global_vars = v;
 }
 
+/* Allocate a new pdb_type for a bitfield. */
+static struct pdb_type *
+find_type_bitfield (struct pdb_type *underlying_type, unsigned int size,
+   unsigned int offset)
+{
+  struct pdb_type *type, *last_entry = NULL;
+  struct pdb_bitfield *bf;
+
+  type = bitfield_types;
+  while (type)
+{
+  bf = (struct pdb_bitfield *) type->data;
+
+  if (bf->underlying_type == underlying_type && bf->size == size
+ && bf->offset == offset)
+   return type;
+
+  last_entry = type;
+  type = type->next2;
+}
+
+  type =
+(struct pdb_type *) xmalloc (offsetof (struct pdb_type, data) +
+sizeof (struct pdb_bitfield));
+
+  type->cv_type = LF_BITFIELD;
+  type->tree = NULL;
+  type->next = type->next2 = NULL;
+  type->id = 0;
+
+  bf = (struct pdb_bitfield *) type->data;
+
+  bf->underlying_type = underlying_type;
+  bf->size = size;
+  bf->offset = offset;
+
+  if (last_entry)
+last_entry->next2 = type;
+  else
+bitfield_types = type;
+
+  if (last_type)
+last_type->next = type;
+  else
+types = type;
+
+  last_type = type;
+
+  return type;
+}
+
 /* Allocate a pdb_type for a forward declaration for a struct. The debugger
  * will resolve this automatically, by searching for a substantive
  * struct definition with the same name. */
@@ -1844,8 +1916,25 @@ find_type_struct (tree t, bool is_union)
  ent->fld_attr = CV_FLDATTR_PUBLIC;
  ent->name = xstrdup (IDENTIFIER_POINTER (DECL_NAME (f)));
 
- ent->type = find_type (TREE_TYPE (f));
- ent->offset = bit_offset / 8;
+ if (DECL_BIT_FIELD_TYPE (f))
+   {
+ struct pdb_type *underlying_type =
+   find_type (DECL_BIT_FIELD_TYPE (f));
+
+ ent->type =
+   find_type_bitfield (underlying_type,
+   TREE_INT_CST_ELT (DECL_SIZE (f),
+ 0),
+   TREE_INT_CST_ELT
+   (DECL_FIELD_BIT_OFFSET (f), 0));
+ ent->offset =
+   TREE_INT_CST_ELT (DECL_FIELD_OFFSET (f), 0);
+   }
+ else
+   {
+ ent->type = find_type (TREE_TYPE (f));
+ ent->offset = bit_offset / 8;
+   }
 
  ent++;
}
diff --git a/gcc/pdbout.h b/gcc/pdbout.h
index 09b3914d650..e12f1cf21a0 100644
--- a/gcc/pdbout.h
+++ b/gcc/pdbout.h
@@ -37,6 +37,7 @@
 #define S_DEFRANGE_REGISTER_REL0x1145
 #define LF_ARGLIST 0x1201
 #define LF_FIELDLIST   0x1203
+#define LF_BITFIELD0x1205
 #define LF_ENUMERATE   0x1502
 #define LF_ARRAY   0x1503
 #define LF_CLASS   0x1504
@@ -373,6 +374,13 @@ struct pdb_modifier
   uint16_t modifier;
 };
 
+struct pdb_bitfie

[PATCH 17/24] pdbout: Prepend namespaces to struct and function names.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 93 ++--
 1 file changed, 91 insertions(+), 2 deletions(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index d3f251f22d2..fb40f066bd9 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -1484,24 +1484,113 @@ pdbout_finish (const char *filename ATTRIBUTE_UNUSED)
   write_pdb_type_section ();
 }
 
-/* For a tree t, construct the name. */
+/* For a tree t, construct the name - namespaces, plus the
+ * base name of the tree. */
 static char *
 get_tree_name (tree t)
 {
   char *name;
+  tree ns;
+
+  static const char anon_ns[] = "";
 
   if (TREE_CODE (t) == FUNCTION_DECL)
 name = xstrdup (IDENTIFIER_POINTER (DECL_NAME (t)));
   else if (TYPE_NAME (t) && TREE_CODE (TYPE_NAME (t)) == IDENTIFIER_NODE)
 name = xstrdup (IDENTIFIER_POINTER (TYPE_NAME (t)));
   else if (TYPE_NAME (t) && TREE_CODE (TYPE_NAME (t)) == TYPE_DECL
-&& IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t)))[0] != '.')
+  && IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t)))[0] != '.')
 name = xstrdup (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t;
   else if (DECL_NAME (t) && TREE_CODE (DECL_NAME (t)) == IDENTIFIER_NODE)
 name = xstrdup (IDENTIFIER_POINTER (DECL_NAME (t)));
   else
 return NULL;
 
+  /* Prepend any namespaces, if present */
+
+  if (TYPE_NAME (t) && TREE_CODE (TYPE_NAME (t)) == TYPE_DECL)
+ns = DECL_CONTEXT (TYPE_NAME (t));
+  else if (DECL_NAME (t))
+ns = DECL_CONTEXT (t);
+  else
+ns = NULL;
+
+  if (ns)
+{
+  if (TREE_CODE (ns) == NAMESPACE_DECL)
+   {
+ tree orig_ns = ns;
+ size_t ns_len = 0;
+
+ while (ns && TREE_CODE (ns) == NAMESPACE_DECL)
+   {
+ if (DECL_NAME (ns))
+   ns_len += strlen (IDENTIFIER_POINTER (DECL_NAME (ns))) + 2;
+ else
+   ns_len += sizeof (anon_ns) - 1 + 2;
+
+ ns = DECL_CONTEXT (ns);
+   }
+
+ if (ns_len > 0)
+   {
+ char *tmp, *s;
+ size_t name_len = strlen (name);
+
+ tmp = (char *) xmalloc (name_len + ns_len + 1);
+ memcpy (&tmp[ns_len], name, name_len + 1);
+ free (name);
+ name = tmp;
+
+ ns = orig_ns;
+ s = &name[ns_len];
+
+ while (ns && TREE_CODE (ns) == NAMESPACE_DECL)
+   {
+ size_t len;
+
+ s -= 2;
+ memcpy (s, "::", 2);
+
+ if (DECL_NAME (ns))
+   {
+ len = strlen (IDENTIFIER_POINTER (DECL_NAME (ns)));
+ s -= len;
+ memcpy (s, IDENTIFIER_POINTER (DECL_NAME (ns)), len);
+   }
+ else
+   {
+ s -= sizeof (anon_ns) - 1;
+ memcpy (s, anon_ns, sizeof (anon_ns) - 1);
+   }
+
+ ns = DECL_CONTEXT (ns);
+   }
+   }
+   }
+  else if (TREE_CODE (ns) == RECORD_TYPE
+  || TREE_CODE (ns) == FUNCTION_DECL)
+   {
+ char *s = get_tree_name (ns);
+ char *tmp;
+ size_t name_len = strlen (name);
+ size_t s_len = s ? strlen (s) : 1;
+
+ tmp = (char *) xmalloc (name_len + s_len + 3);
+ memcpy (&tmp[s_len + 2], name, name_len + 1);
+ free (name);
+ name = tmp;
+
+ if (s)
+   memcpy (name, s, s_len);
+ else
+   name[0] = '?';
+
+ name[s_len] = ':';
+ name[s_len + 1] = ':';
+   }
+}
+
   return name;
 }
 
-- 
2.26.2



[PATCH 18/24] pdbout: Append template information to struct or function name.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 346 ++-
 1 file changed, 344 insertions(+), 2 deletions(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index fb40f066bd9..0cae4d33469 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -73,6 +73,7 @@ static void pdbout_end_block (unsigned int line 
ATTRIBUTE_UNUSED,
  unsigned int blocknum);
 
 static struct pdb_type *find_type (tree t);
+static char *get_tree_name (tree t);
 
 static struct pdb_func *funcs = NULL, *cur_func = NULL;
 static struct pdb_block *cur_block = NULL;
@@ -1484,13 +1485,264 @@ pdbout_finish (const char *filename ATTRIBUTE_UNUSED)
   write_pdb_type_section ();
 }
 
+/* Reallocate the string n, adding the type name of arg and the character
+ * suffix.
+ * We can't use the C++ pretty printer for this as this file gets
+ * compiled into libbackend.a. */
+static void
+append_template_element (char **n, size_t *len, tree arg, char suffix)
+{
+  char *tmp;
+  char *name = *n;
+
+  switch (TREE_CODE (arg))
+{
+case RECORD_TYPE:
+case UNION_TYPE:
+  {
+   char *s = get_tree_name (arg);
+
+   if (s)
+ {
+   size_t s_len = strlen (s);
+
+   tmp = (char *) xmalloc (*len + s_len + 2);
+   memcpy (tmp, name, *len);
+   free (name);
+   name = tmp;
+
+   memcpy (&name[*len], s, s_len);
+   name[*len + s_len] = suffix;
+   name[*len + s_len + 1] = 0;
+   *len += s_len + 1;
+
+   free (s);
+ }
+   else
+ {
+   tmp = (char *) xmalloc (*len + 3);
+   memcpy (tmp, name, *len);
+   free (name);
+   name = tmp;
+
+   name[*len] = '?';
+   name[*len + 1] = suffix;
+   name[*len + 2] = 0;
+   *len += 2;
+ }
+
+   break;
+  }
+
+case INTEGER_TYPE:
+case BOOLEAN_TYPE:
+case REAL_TYPE:
+case VOID_TYPE:
+case NULLPTR_TYPE:
+case ENUMERAL_TYPE:
+  {
+   const char *s;
+   size_t s_len;
+
+   if (TREE_CODE (arg) == NULLPTR_TYPE)
+ s = "std::nullptr_t";
+   else
+ s = IDENTIFIER_POINTER (TYPE_IDENTIFIER (arg));
+
+   s_len = strlen (s);
+
+   tmp = (char *) xmalloc (*len + s_len + 2);
+   memcpy (tmp, name, *len);
+   free (name);
+   name = tmp;
+
+   memcpy (&name[*len], s, s_len);
+   name[*len + s_len] = suffix;
+   name[*len + s_len + 1] = 0;
+   *len += s_len + 1;
+
+   break;
+  }
+
+case POINTER_TYPE:
+  {
+   append_template_element (&name, len, TREE_TYPE (arg), '*');
+
+   tmp = (char *) xmalloc (*len + 2);
+   memcpy (tmp, name, *len);
+   free (name);
+   name = tmp;
+
+   name[*len] = suffix;
+   name[*len + 1] = 0;
+   (*len)++;
+
+   break;
+  }
+
+case INTEGER_CST:
+  if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
+   {
+ if (TREE_INT_CST_ELT_CHECK (arg, 0) == 0)
+   {
+ static const char str[] = "false";
+
+ tmp = (char *) xmalloc (*len + sizeof (str) + 2);
+ memcpy (tmp, name, *len);
+ free (name);
+ name = tmp;
+
+ memcpy (&name[*len], str, sizeof (str) - 1);
+ name[*len + sizeof (str) - 1] = suffix;
+ name[*len + sizeof (str)] = 0;
+ *len += sizeof (str);
+   }
+ else
+   {
+ static const char str[] = "true";
+
+ tmp = (char *) xmalloc (*len + sizeof (str) + 2);
+ memcpy (tmp, name, *len);
+ free (name);
+ name = tmp;
+
+ memcpy (&name[*len], str, sizeof (str) - 1);
+ name[*len + sizeof (str) - 1] = suffix;
+ name[*len + sizeof (str)] = 0;
+ *len += sizeof (str);
+   }
+   }
+  else
+   {
+ char s[50];
+ size_t s_len;
+
+ if (TYPE_UNSIGNED (arg))
+   sprintf (s, "%lu", TREE_INT_CST_ELT_CHECK (arg, 0));
+ else
+   sprintf (s, "%li", TREE_INT_CST_ELT_CHECK (arg, 0));
+
+ s_len = strlen (s);
+
+ tmp = (char *) xmalloc (*len + s_len + 2);
+ memcpy (tmp, name, *len);
+ free (name);
+ name = tmp;
+
+ memcpy (&name[*len], s, s_len);
+ name[*len + s_len] = suffix;
+ name[*len + s_len + 1] = 0;
+ *len += s_len + 1;
+   }
+  break;
+
+case REFERENCE_TYPE:
+  {
+   append_template_element (&name, len, TREE_TYPE (arg), '&');
+
+   tmp = (char *) xmalloc (*len + 2);
+   memcpy (tmp, name, *len);
+   free (name);
+   name = tmp;
+
+   name[*len] = suffix;
+   name[*len + 1] = 0;
+   (*len)++;
+
+   break;
+  }
+
+case TYPE_ARGUMENT_PACK:
+  {
+   static const char str[] = "...";
+
+   tmp = (char *) xmalloc (*len + sizeof (str) + 2);
+   memcpy (tmp, name, *len);
+   free (name);

[PATCH 19/24] pdbout: Handle typedefs to anonymous types.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 79 +++-
 1 file changed, 78 insertions(+), 1 deletion(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index 0cae4d33469..dae5c1ef679 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -3344,6 +3344,8 @@ alias_hasher::equal (const value_type type, compare_type 
tree)
 static void
 pdbout_type_decl (tree t, int local ATTRIBUTE_UNUSED)
 {
+  struct pdb_type *type;
+
   /* We need to record the typedefs to ensure e.g. that Windows'
* LPWSTR gets mapped to wchar_t* rather than uint16_t*.
* There is a LF_ALIAS / lfAlias in Microsoft's header files, but
@@ -3365,6 +3367,47 @@ pdbout_type_decl (tree t, int local ATTRIBUTE_UNUSED)
  && !strcmp (IDENTIFIER_POINTER (DECL_NAME (t)), "HRESULT"))
a->type = hresult_type;
 
+  // give name if previously anonymous
+
+  if (a->type)
+   {
+ switch (a->type->cv_type)
+   {
+   case LF_STRUCTURE:
+   case LF_CLASS:
+   case LF_UNION:
+ {
+   struct pdb_struct *str = (struct pdb_struct *) a->type->data;
+
+   if (!str->name)
+ {
+   struct pdb_type **slot;
+
+   str->name = xstrdup (IDENTIFIER_POINTER (DECL_NAME (t)));
+
+   slot =
+ struct_hash_table.find_slot_with_hash (str->name,
+struct_hasher::
+hash (str->name),
+INSERT);
+   *slot = a->type;
+ }
+
+   break;
+ }
+
+   case LF_ENUM:
+ {
+   struct pdb_enum *en = (struct pdb_enum *) a->type->data;
+
+   if (!en->name)
+ en->name = xstrdup (IDENTIFIER_POINTER (DECL_NAME (t)));
+
+   break;
+ }
+   }
+   }
+
   slot =
alias_hash_table.find_slot_with_hash (TREE_TYPE (t),
  htab_hash_pointer (TREE_TYPE
@@ -3377,7 +3420,41 @@ pdbout_type_decl (tree t, int local ATTRIBUTE_UNUSED)
   return;
 }
 
-  find_type (TREE_TYPE (t));
+  type = find_type (TREE_TYPE (t));
+
+  if (!type || type->id != 0)
+return;
+
+  if (DECL_NAME (t) && IDENTIFIER_POINTER (DECL_NAME (t))
+  && IDENTIFIER_POINTER (DECL_NAME (t))[0] != '.')
+{
+  // give name if previously anonymous
+
+  switch (type->cv_type)
+   {
+   case LF_STRUCTURE:
+   case LF_CLASS:
+   case LF_UNION:
+ {
+   struct pdb_struct *str = (struct pdb_struct *) type->data;
+
+   if (!str->name)
+ str->name = xstrdup (IDENTIFIER_POINTER (DECL_NAME (t)));
+
+   break;
+ }
+
+   case LF_ENUM:
+ {
+   struct pdb_enum *en = (struct pdb_enum *) type->data;
+
+   if (!en->name)
+ en->name = xstrdup (IDENTIFIER_POINTER (DECL_NAME (t)));
+
+   break;
+ }
+   }
+}
 }
 
 #ifndef _WIN32
-- 
2.26.2



[PATCH 20/24] pdbout: Output file and line number of type definitions.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 208 ++-
 gcc/pdbout.h |  10 +++
 2 files changed, 217 insertions(+), 1 deletion(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index dae5c1ef679..8dbd8f58a87 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -79,6 +79,7 @@ static struct pdb_func *funcs = NULL, *cur_func = NULL;
 static struct pdb_block *cur_block = NULL;
 static struct pdb_global_var *global_vars = NULL;
 static struct pdb_type *types = NULL, *last_type = NULL;
+static struct pdb_type *string_types = NULL;
 static struct pdb_type *arglist_types = NULL;
 static struct pdb_type *pointer_types = NULL;
 static struct pdb_type *proc_types = NULL;
@@ -1301,6 +1302,53 @@ write_procedure (struct pdb_proc *proc)
   fprintf (asm_out_file, "\t.short\t0\n"); // padding
 }
 
+/* Output lfStringId structure. */
+static void
+write_string_id (struct pdb_type *t)
+{
+  size_t string_len = strlen ((const char *) t->data);
+  size_t len = 9 + string_len, align;
+
+  if (len % 4 != 0)
+align = 4 - (len % 4);
+  else
+align = 0;
+
+  len += align;
+
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+  (uint16_t) (len - sizeof (uint16_t)));
+  fprintf (asm_out_file, "\t.short\t0x%x\n", LF_STRING_ID);
+  fprintf (asm_out_file, "\t.long\t0\n");
+  ASM_OUTPUT_ASCII (asm_out_file, (const char *) t->data, string_len + 1);
+
+  if (align == 3)
+fprintf (asm_out_file, "\t.byte\t0xf3\n");
+
+  if (align >= 2)
+fprintf (asm_out_file, "\t.byte\t0xf2\n");
+
+  if (align >= 1)
+fprintf (asm_out_file, "\t.byte\t0xf1\n");
+}
+
+/* Output lfUdtSrcLine structure, describing on which line in a file a
+ * type is defined. The linker transforms this into a lfUdtModSrcLine
+ * structure (LF_UDT_MOD_SRC_LINE), which also adds details of the
+ * "module" (i.e. object file). */
+static void
+write_udt_src_line (struct pdb_udt_src_line *t)
+{
+  fprintf (asm_out_file, "\t.short\t0xe\n");
+  fprintf (asm_out_file, "\t.short\t0x%x\n", LF_UDT_SRC_LINE);
+  fprintf (asm_out_file, "\t.short\t0x%x\n", t->type ? t->type->id : 0);
+  fprintf (asm_out_file, "\t.short\t0\n"); // padding
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+  t->source_file ? t->source_file->id : 0);
+  fprintf (asm_out_file, "\t.short\t0\n"); // padding
+  fprintf (asm_out_file, "\t.long\t0x%x\n", t->line);
+}
+
 /* Output lfModifier structure, representing a const or volatile version
  * of an existing type. */
 static void
@@ -1372,6 +1420,14 @@ write_type (struct pdb_type *t)
   write_procedure ((struct pdb_proc *) t->data);
   break;
 
+case LF_STRING_ID:
+  write_string_id (t);
+  break;
+
+case LF_UDT_SRC_LINE:
+  write_udt_src_line ((struct pdb_udt_src_line *) t->data);
+  break;
+
 case LF_MODIFIER:
   write_modifier ((struct pdb_modifier *) t->data);
   break;
@@ -2029,6 +2085,7 @@ find_type_bitfield (struct pdb_type *underlying_type, 
unsigned int size,
   type->tree = NULL;
   type->next = type->next2 = NULL;
   type->id = 0;
+  type->udt_src_line = NULL;
 
   bf = (struct pdb_bitfield *) type->data;
 
@@ -2081,6 +2138,7 @@ add_struct_forward_declaration (tree t, const char *name)
   strtype->tree = NULL;
   strtype->next = strtype->next2 = NULL;
   strtype->id = 0;
+  strtype->udt_src_line = NULL;
 
   str = (struct pdb_struct *) strtype->data;
   str->count = 0;
@@ -2195,6 +2253,7 @@ add_type_fieldlist (struct pdb_type *t)
 
   t->next = t->next2 = NULL;
   t->id = 0;
+  t->udt_src_line = NULL;
 
   if (last_entry)
 last_entry->next2 = t;
@@ -2459,6 +2518,7 @@ find_type_struct (tree t, bool is_union)
 
   strtype->next = strtype->next2 = NULL;
   strtype->id = 0;
+  strtype->udt_src_line = NULL;
 
   str = (struct pdb_struct *) strtype->data;
   str->count = num_entries;
@@ -2539,6 +2599,7 @@ find_type_array (tree t)
   arrtype->tree = t;
   arrtype->next = arrtype->next2 = NULL;
   arrtype->id = 0;
+  arrtype->udt_src_line = NULL;
 
   arr = (struct pdb_array *) arrtype->data;
   arr->type = type;
@@ -2607,6 +2668,7 @@ add_arglist_type (struct pdb_type *t)
 
   t->next = NULL;
   t->next2 = NULL;
+  t->udt_src_line = NULL;
   t->id = 0;
 
   if (last_type)
@@ -2725,6 +2787,7 @@ find_type_enum (tree t)
   enumtype->tree = t;
   enumtype->next = enumtype->next2 = NULL;
   enumtype->id = 0;
+  enumtype->udt_src_line = NULL;
 
   en = (struct pdb_enum *) enumtype->data;
   en->count = num_entries;
@@ -2798,6 +2861,7 @@ find_type_pointer (tree t)
   ptrtype->tree = t;
   ptrtype->next = ptrtype->next2 = NULL;
   ptrtype->id = 0;
+  ptrtype->udt_src_line = NULL;
 
   ptr = (struct pdb_pointer *) ptrtype->data;
   ptr->type = type;
@@ -2925,6 +2989,7 @@ find_type_function (tree t)
   proctype->tree = t;
   proctype->next = proctype->next2 = NULL;
   proctype->id = 0;
+  proctype->udt_src_line = NULL;
 
   proc = (struct pdb_proc *) proctype->data;
 
@@ -2990,6 +3055,7 @@ find_type_modifier (tree t)
   type->tree = t;
   type->next = type->next2 = NULL;
   t

[PATCH 21/24] pdbout: Don't output unused types.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 256 ++-
 gcc/pdbout.h |   1 +
 2 files changed, 254 insertions(+), 3 deletions(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index 8dbd8f58a87..3d15c620db5 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -1438,7 +1438,8 @@ write_type (struct pdb_type *t)
 }
 }
 
-/* Output the .debug$T section, which contains all the types used. */
+/* Output the .debug$T section, which contains all the types used.
+ * Types defined but not used will not be output. */
 static void
 write_pdb_type_section (void)
 {
@@ -1450,7 +1451,8 @@ write_pdb_type_section (void)
   n = types;
   while (n)
 {
-  write_type (n);
+  if (n->used)
+   write_type (n);
 
   n = n->next;
 }
@@ -1476,6 +1478,227 @@ write_pdb_type_section (void)
 }
 }
 
+/* Loop through our list of types. If a type is marked as used but a type
+ * it refers to isn't, marked that type as used too. */
+static void
+mark_referenced_types_used (void)
+{
+  struct pdb_type *t;
+  bool changed;
+
+  do
+{
+  changed = false;
+
+  t = types;
+  while (t)
+   {
+ if (!t->used)
+   {
+ t = t->next;
+ continue;
+   }
+
+ if (t->udt_src_line && !t->udt_src_line->used)
+   {
+ t->udt_src_line->used = true;
+ changed = true;
+   }
+
+ switch (t->cv_type)
+   {
+   case LF_MODIFIER:
+ {
+   struct pdb_modifier *mod = (struct pdb_modifier *) t->data;
+
+   if (mod->type && !mod->type->used)
+ {
+   mod->type->used = true;
+   changed = true;
+ }
+
+   break;
+ }
+
+   case LF_POINTER:
+ {
+   struct pdb_pointer *ptr = (struct pdb_pointer *) t->data;
+
+   if (ptr->type && !ptr->type->used)
+ {
+   ptr->type->used = true;
+   changed = true;
+ }
+
+   break;
+ }
+
+   case LF_PROCEDURE:
+ {
+   struct pdb_proc *proc = (struct pdb_proc *) t->data;
+
+   if (proc->arg_list && !proc->arg_list->used)
+ {
+   proc->arg_list->used = true;
+   changed = true;
+ }
+
+   if (proc->return_type && !proc->return_type->used)
+ {
+   proc->return_type->used = true;
+   changed = true;
+ }
+
+   break;
+ }
+
+   case LF_ARGLIST:
+ {
+   struct pdb_arglist *al = (struct pdb_arglist *) t->data;
+
+   for (unsigned int i = 0; i < al->count; i++)
+ {
+   if (al->args[i] && !al->args[i]->used)
+ {
+   al->args[i]->used = true;
+   changed = true;
+ }
+ }
+
+   break;
+ }
+
+   case LF_FIELDLIST:
+ {
+   struct pdb_fieldlist *fl = (struct pdb_fieldlist *) t->data;
+
+   for (unsigned int i = 0; i < fl->count; i++)
+ {
+   if (fl->entries[i].type && !fl->entries[i].type->used)
+ {
+   fl->entries[i].type->used = true;
+   changed = true;
+ }
+ }
+
+   break;
+ }
+
+   case LF_BITFIELD:
+ {
+   struct pdb_bitfield *bf = (struct pdb_bitfield *) t->data;
+
+   if (bf->underlying_type && !bf->underlying_type->used)
+ {
+   bf->underlying_type->used = true;
+   changed = true;
+ }
+
+   break;
+ }
+
+   case LF_ARRAY:
+ {
+   struct pdb_array *arr = (struct pdb_array *) t->data;
+
+   if (arr->type && !arr->type->used)
+ {
+   arr->type->used = true;
+   changed = true;
+ }
+
+   if (arr->index_type && !arr->index_type->used)
+ {
+   arr->index_type->used = true;
+   changed = true;
+ }
+
+   break;
+ }
+
+   case LF_CLASS:
+   case LF_STRUCTURE:
+   case LF_UNION:
+ {
+   struct pdb_struct *str = (struct pdb_struct *) t->data;
+
+   if (str->field_type && !str->field_type->used)
+ {
+   str->field_type->used = true;
+   changed = true;
+ }
+
+   // forward declarations should propagate usedness
+   // to actual types
+   if (str->property.s

[PATCH 22/24] pdbout: Split large fieldlists when necessary.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 151 ++-
 gcc/pdbout.h |   1 +
 2 files changed, 151 insertions(+), 1 deletion(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index 3d15c620db5..d9ad659cd9a 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -84,7 +84,7 @@ static struct pdb_type *arglist_types = NULL;
 static struct pdb_type *pointer_types = NULL;
 static struct pdb_type *proc_types = NULL;
 static struct pdb_type *modifier_types = NULL;
-static struct pdb_type *fieldlist_types = NULL;
+static struct pdb_type *fieldlist_types = NULL, *last_fieldlist_type = NULL;
 static struct pdb_type *struct_types = NULL, *last_struct_type = NULL;
 static struct pdb_type *enum_types = NULL;
 static struct pdb_type *bitfield_types = NULL;
@@ -911,6 +911,10 @@ write_fieldlist (struct pdb_fieldlist *fl)
len += strlen (fl->entries[i].name);
 
  break;
+
+   case LF_INDEX:
+ len += 6;
+ break;
}
 
   if (len % 4 != 0)
@@ -1055,6 +1059,12 @@ write_fieldlist (struct pdb_fieldlist *fl)
 
break;
  }
+
+   case LF_INDEX:
+ fprintf (asm_out_file, "\t.short\t0\n"); // padding
+ fprintf (asm_out_file, "\t.short\t0x%x\n", fl->entries[i].type->id);
+ fprintf (asm_out_file, "\t.short\t0\n"); // padding
+ break;
}
 }
 }
@@ -1753,6 +1763,141 @@ number_types (void)
 }
 }
 
+/* The maximum length for a type entry is 0x. If we have a fieldlist
+ * which would be more than that we need to split it, adding an LF_INDEX
+ * entry to point to the continuation entry. */
+static void
+split_large_fieldlists ()
+{
+  struct pdb_type *t = types;
+  struct pdb_type *prev = NULL;
+
+  while (t)
+{
+  struct pdb_fieldlist *fl;
+  unsigned int len, max_len;
+  bool made_split = false;
+
+  if (t->cv_type != LF_FIELDLIST || !t->used)
+   {
+ prev = t;
+ t = t->next;
+ continue;
+   }
+
+  fl = (struct pdb_fieldlist *) t->data;
+
+  /* Maximum length of 0x, minus 8 bytes for the LF_INDEX we might
+   * need to add, rounded down to multiple of 4. */
+  max_len = 0xfff4;
+  len = sizeof (uint16_t) + sizeof (uint16_t); // length + LF_FIELDLIST
+
+  for (int i = fl->count - 1; i >= 0; i--) {
+ unsigned int delta;
+
+ delta = 2; // LF_MEMBER, LF_ENUMERATE, or LF_INDEX
+
+ switch (fl->entries[i].cv_type) {
+   case LF_MEMBER:
+ delta += 9;
+ break;
+
+   case LF_ENUMERATE:
+ delta += 5;
+
+ /* Positive values less than 0x8000 are stored as they are;
+  * otherwise we prepend two bytes describing what type it is. */
+
+ if (fl->entries[i].value >= 0x8000 || fl->entries[i].value < 0)
+   {
+ if (fl->entries[i].value >= -127 && fl->entries[i].value < 0)
+   delta++;// LF_CHAR
+ else if (fl->entries[i].value >= -0x7fff &&
+ fl->entries[i].value <= 0x7fff)
+   {
+ delta += 2;   // LF_SHORT
+   }
+ else if (fl->entries[i].value >= 0x8000 &&
+ fl->entries[i].value <= 0x)
+   {
+ delta += 2;   // LF_USHORT
+   }
+ else if (fl->entries[i].value >= -0x7fff &&
+ fl->entries[i].value <= 0x7fff)
+   {
+ delta += 4;   // LF_LONG
+   }
+ else if (fl->entries[i].value >= 0x8000 &&
+ fl->entries[i].value <= 0x)
+   {
+ delta += 4;   // LF_ULONG
+   }
+ else
+   delta += 8; // LF_QUADWORD or LF_UQUADWORD
+   }
+ break;
+
+   case LF_INDEX:
+ delta += 6;
+ break;
+ }
+
+ if (fl->entries[i].name)
+   delta += strlen (fl->entries[i].name);
+
+ if (delta % 4 != 0)
+   delta += 4 - (delta % 4);
+
+ if (len + delta > max_len)
+   {
+ struct pdb_type *t2;
+ struct pdb_fieldlist *fl2;
+ unsigned int num_entries = fl->count - i - 1;
+
+ t2 =
+   (struct pdb_type *) xmalloc (offsetof (struct pdb_type, data) +
+ offsetof (struct pdb_fieldlist, entries) +
+ (num_entries * sizeof (struct pdb_fieldlist_entry)));
+ t2->cv_type = LF_FIELDLIST;
+ t2->next = t;
+ t2->tree = NULL;
+ t2->used = true;
+ t2->id = 0;
+
+ if (prev)
+   prev->next = t2;
+ else
+   types = t2;
+
+ fl2 = (struct pdb_fieldlist *) t2->data;
+ fl2->count = num_

[PATCH 24/24] pdbout: Handle functions with parts in cold section.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 226 ++-
 gcc/pdbout.h |   2 +
 2 files changed, 170 insertions(+), 58 deletions(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index 0f5315f7f07..b4528fb79e8 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -71,6 +71,7 @@ static void pdbout_begin_block (unsigned int line 
ATTRIBUTE_UNUSED,
unsigned int blocknum);
 static void pdbout_end_block (unsigned int line ATTRIBUTE_UNUSED,
  unsigned int blocknum);
+static void pdbout_new_section (void);
 
 static struct pdb_type *find_type (tree t);
 static char *get_tree_name (tree t);
@@ -145,7 +146,7 @@ const struct gcc_debug_hooks pdb_debug_hooks = {
   pdbout_var_location,
   debug_nothing_tree,  /* inline_entry */
   debug_nothing_tree,  /* size_function */
-  debug_nothing_void,  /* switch_text_section */
+  pdbout_new_section,
   debug_nothing_tree_tree, /* set_name */
   0,   /* start_end_main_source_file */
   TYPE_SYMTAB_IS_ADDRESS   /* tree_type_symtab_field */
@@ -157,8 +158,8 @@ pdbout_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
   unsigned int column ATTRIBUTE_UNUSED,
   const char *file ATTRIBUTE_UNUSED)
 {
-  fprintf (asm_out_file, FUNC_BEGIN_LABEL "%u:\n",
-  current_function_funcdef_no);
+  fprintf (asm_out_file, FUNC_BEGIN_LABEL "%s%u:\n",
+  in_cold_section_p ? "cold" : "", current_function_funcdef_no);
 }
 
 /* Add label after function end */
@@ -166,7 +167,8 @@ static void
 pdbout_end_epilogue (unsigned int line ATTRIBUTE_UNUSED,
 const char *file ATTRIBUTE_UNUSED)
 {
-  fprintf (asm_out_file, FUNC_END_LABEL "%u:\n", current_function_funcdef_no);
+  fprintf (asm_out_file, FUNC_END_LABEL "%s%u:\n",
+  in_cold_section_p ? "cold" : "", current_function_funcdef_no);
 }
 
 /* Output DEFRANGESYMREGISTER or DEFRANGESYMREGISTERREL structure, describing
@@ -464,8 +466,8 @@ pdbout_block (struct pdb_block *block, struct pdb_func 
*func)
}
   else
{
- fprintf (asm_out_file, "\t.long\t[.Lcvprocstart%u]-[.debug$S]\n",
-  func->num);
+ fprintf (asm_out_file, "\t.long\t[.Lcvprocstart%s%u]-[.debug$S]\n",
+  func->cold ? "cold" : "", func->num);
}
 
   fprintf (asm_out_file, "\t.long\t[.Lcvblockend%u]-[.debug$S]\n",
@@ -497,61 +499,72 @@ pdbout_block (struct pdb_block *block, struct pdb_func 
*func)
 static void
 pdbout_proc32 (struct pdb_func *func)
 {
-  size_t name_len = func->name ? strlen (func->name) : 0;
-  uint16_t len = 40 + name_len, align;
-
-  // start procedure
+  /* Don't output function definition if it contains no lines. This can happen
+   * if the compiler creates a cold function consisting of just ud2. */
 
-  if (len % 4 != 0)
+  if (func->lines)
 {
-  align = 4 - (len % 4);
-  len += 4 - (len % 4);
-}
-  else
-align = 0;
+  size_t name_len = func->name ? strlen (func->name) : 0;
+  uint16_t len = 40 + name_len, align;
 
-  fprintf (asm_out_file, ".Lcvprocstart%u:\n", func->num);
-  fprintf (asm_out_file, "\t.short\t0x%x\n",
-  (uint16_t) (len - sizeof (uint16_t)));   // reclen
-  fprintf (asm_out_file, "\t.short\t0x%x\n",
-  func->public_flag ? S_GPROC32 : S_LPROC32);
-  fprintf (asm_out_file, "\t.long\t0\n");  // pParent
-  fprintf (asm_out_file, "\t.long\t[.Lcvprocend%u]-[.debug$S]\n",
-  func->num);  // pEnd
-  fprintf (asm_out_file, "\t.long\t0\n");  // pNext
-  fprintf (asm_out_file,
-  "\t.long\t[" FUNC_END_LABEL "%u]-[" FUNC_BEGIN_LABEL "%u]\n",
-  func->num, func->num);   // len
-  fprintf (asm_out_file, "\t.long\t0\n");  // DbgStart
-  fprintf (asm_out_file, "\t.long\t0\n");  // DbgEnd
-  fprintf (asm_out_file, "\t.short\t0x%x\n", func->type ? func->type->id : 0);
-  fprintf (asm_out_file, "\t.short\t0\n"); // padding
 
-  fprintf (asm_out_file, "\t.secrel32\t" FUNC_BEGIN_LABEL "%u\n",
-  func->num);  // offset
-  fprintf (asm_out_file, "\t.secidx\t" FUNC_BEGIN_LABEL "%u\n",
-  func->num);  // section
+  // start procedure
 
-  fprintf (asm_out_file, "\t.byte\t0\n");  // flags
+  if (len % 4 != 0)
+   {
+ align = 4 - (len % 4);
+ len += 4 - (len % 4);
+   }
+  else
+   align = 0;
 
-  if (func->name)
-ASM_OUTPUT_ASCII (asm_out_file, func->name, name_len + 1);
-  else
-fprintf (asm_out_file, "\t.byte\t0\n");
+  fprintf (asm_out_file, ".Lcvprocstart%s%u:\n",
+ func->cold ? "cold" : "", func->num);
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+ (uint16_t) (len - sizeof (uint16_t)));// reclen
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+ func->public_flag ? S_GPROC32 : S_LPROC32);
+  fprintf (asm_out_file, "\t.long\t0\n");  // pParent
+  fprintf (asm_out_file, "\t.lo

[PATCH 23/24] pdbout: Handle names of ctor and dtor functions.

2021-03-20 Thread Mark Harmstone
---
 gcc/pdbout.c | 28 +++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index d9ad659cd9a..0f5315f7f07 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -2175,7 +2175,33 @@ get_tree_name (tree t)
   static const char anon_ns[] = "";
 
   if (TREE_CODE (t) == FUNCTION_DECL)
-name = xstrdup (IDENTIFIER_POINTER (DECL_NAME (t)));
+{
+  if (DECL_CXX_CONSTRUCTOR_P (t) || DECL_CXX_DESTRUCTOR_P (t))
+   {
+ tree ctx = DECL_CONTEXT (t);
+ const char *basename;
+
+ if (!ctx || !TYPE_NAME (ctx)
+ || TREE_CODE (TYPE_NAME (ctx)) != TYPE_DECL)
+   return NULL;
+
+ basename = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (ctx)));
+
+ if (DECL_CXX_CONSTRUCTOR_P (t))
+   name = xstrdup (basename);
+ else
+   {
+ name = (char *) xmalloc (strlen (basename) + 2);
+
+ name[0] = '~';
+ name[1] = 0;
+
+ strcat (name, basename);
+   }
+   }
+  else
+   name = xstrdup (IDENTIFIER_POINTER (DECL_NAME (t)));
+}
   else if (TYPE_NAME (t) && TREE_CODE (TYPE_NAME (t)) == IDENTIFIER_NODE)
 name = xstrdup (IDENTIFIER_POINTER (TYPE_NAME (t)));
   else if (TYPE_NAME (t) && TREE_CODE (TYPE_NAME (t)) == TYPE_DECL
-- 
2.26.2



Re: [wwwdocs] arm,aarc64: add initial gcc-11/changes.html entries

2021-03-20 Thread Gerald Pfeifer
Hi Kyrylo,

On Tue, 26 Jan 2021, Kyrylo Tkachov via Gcc-patches wrote:
> This patch adds the arm and aarch64 sections changes.html for GCC 11.

this is nice!

One question: why GCC 11.0 in the following? The first release is going 
to be GCC 11.1, and we general refer to major releases - could we say
"GCC 11" instead? Or do you want to use GCC 11.1?

+  The availability of Advanced SIMD intrinsics available through the
+  arm_neon.h header is improved and GCC 11.0 supports the full
+  set of intrinsics defined by ACLE Q3 2020.


> There's more than that that went into the release, but this can serve as 
> a starting point for filling the sections in.

Looking forward to more! :)

Gerald


Re: [PING][PATCH] adjust "partly out of bounds" warning (PR 98503)

2021-03-20 Thread Jeff Law via Gcc-patches



On 3/18/2021 4:18 PM, Martin Sebor via Gcc-patches wrote:

Ping:
https://gcc.gnu.org/pipermail/gcc-patches/2021-January/564483.html

The review of this patch digressed into a design discussion of a new,
more capable implementation of -Wstrict-aliasing, but the proposed
patch turning just this one instance of -Warray-bounds into
-Wstrict-aliasing and making it subject to -fstrict-aliasing wasn't
decided.  PR 98503 was raised by someone working with the kernel
which uses -fno-strict-aliasing, and so to them the warning isn't
useful.  But since the warning does find potential bugs when strict
aliasing is in effect, I'd still like to consider this patch for
GCC 11 so that the kernel (and other such projects) doesn't have
to deal with the false positives.

If/when we add a new, dedicated solution for -Wstrict-aliasing I'll
move this instance from gimple-array-bounds.cc there.


I'm still not comfortable with the bleeding of strict aliasing bits into 
the gimple array-bounds checking bits.  I think that needs to be fixed 
in a cleaner manner before this can go forward.



jeff



Re: [PATCH v2] x86: Check cfun != NULL before accessing silent_p

2021-03-20 Thread Uros Bizjak via Gcc-patches
On Sat, Mar 20, 2021 at 4:55 PM H.J. Lu  wrote:
>
> On Sat, Mar 20, 2021 at 6:46 AM Martin Liška  wrote:
> >
> > On 3/20/21 1:21 PM, H.J. Lu wrote:
> > > |Since construct_container may be called with cfun == NULL, check cfun != 
> > > NULL before accessing silent_p. |
> >
> > Thank you for the quick fix.
> >
> > Please use the minimal reproducer for a test-case:
> >
> > $ cat va-arg-pack-1.C
> > #include 
> > void abort() {
> >double ld;
> >va_list ap;
> >ld = va_arg(ap, long double);
> >if (ld)
> >  abort();
> > }
> >
>
> Fixed.  I also added a testcase for SSE register.
>
> Here is the v2 patch.  OK for master?

OK.

Thanks,
Uros.


Re: 回复: [PATCH v4 1/2] MIPS: Not trigger error for pre-R6 and -mcompact-branches=always

2021-03-20 Thread Maciej W. Rozycki
On Sat, 20 Mar 2021, Jeff Law wrote:

> > > I think what you're trying to do here is set up a scenario where you're
> > > defaulting to mips32r6 and compact-branches, but not error if something
> > > specifies -mcpu=mips32r2 or something similar, right?
> > > 
> > Yes. If we introduce the build time option, and configure gcc with always,
> > then gcc will always try to
> > Pass -mconpact-branches=always to cc1, even we use something like:
> >  mipsisa32r6el-linux-gnu-gcc -mips32r2 -c xx.c
> > It may break something.
> 
> So would it be possible to make the mips32rX (for X <6) option also turn off
> compact-branches?   Maciej, is that less problematical from your standpoint? 
> Or is this just ultimately a bad idea from start to finish?

 I don't expect anything to break if we allow `-mcompact-branches=always' 
below R6, whether defaulted or used explicitly.  Given that currently it's 
a hard error, it's not a scenario that anyone could rely on.  I don't know 
offhand if bad code that does not assemble is going to be produced in that 
case, but I doubt it as individual instruction patterns are routinely 
guarded by an ISA level check.

 Also we have some compact branches or jumps to choose from below R6, such 
as with the MIPS16e ISA or the microMIPSr3 ISA, so the option does make 
some sense semantically if not functionally (observe the reservation 
saying: "a compact branch instruction will be generated if available", so 
even now we reserve the right to produce a delay slot form despite the 
option being active, although the wording does imply best efforts).

 Regardless I would not require the option to fully support those ISA 
variations as a prerequisite for YunQiang's change.  I think it would be 
enough if we documented that it is effective for R6+ only (by modifying 
the current note in the manual).  If a need or desire arises, then a 
further update can be made in the future.

 I think this is GCC 12 material however, we're well into a feature freeze 
now and it is not a bug fix.  It will give people plenty of time too to 
run regression testing with `-mcompact-branches=always' combined with a 
representative set of ISA levels.

  Maciej


[PATCH] C++ modules: fix alloc-dealloc-mismatch ASAN issue

2021-03-20 Thread Martin Liška

Hi.

The patch fixes the alloc-dealloc-mismatch reported by ASAN.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

gcc/cp/ChangeLog:

PR c++/99687
* module.cc (fini_modules): Call vec_free instead of delete.
---
 gcc/cp/module.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 6dbdc926cb4..551cb66a6d4 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -20009,7 +20009,7 @@ fini_modules ()
   modules_hash = NULL;
 
   /* Or entity array.  We still need the entity map to find import numbers.  */

-  delete entity_ary;
+  vec_free (entity_ary);
   entity_ary = NULL;
 
   /* Or remember any pending entities.  */

--
2.30.2



Re: [PATCH] Complete __gnu_debug::basic_string

2021-03-20 Thread François Dumont via Gcc-patches
Following your feedback here is the simplified version. I grouped it 
with the patch I submitted before.



On 19/03/21 8:41 pm, Jonathan Wakely wrote:

On 16/03/21 21:55 +0100, François Dumont via Libstdc++ wrote:

Following:

https://gcc.gnu.org/pipermail/libstdc++/2021-March/052158.html

Here is the patch to complete __gnu_debug::basic_string support. 
Contrarily to what I thought code in std::basic_string to generate a 
basic_string_view works just fine for __gnu_debug::basic_string.


    libstdc++: [_GLIBCXX_DEBUG] Add __gnu_debug 
u8string/u16string/u32string


    Complete __gnu_debug::basic_string support so that it can be used 
as a

    transparent replacement of std::basic_string.

    libstdc++-v3/ChangeLog:

    * include/debug/string
    (basic_string(const _CharT*, const _Allocator&)): Remove 
assign call.
    (basic_string<>::insert(const_iterator, _InputIte, 
_InputIte)): Try to

    remove iterator debug layer even if !_GLIBCXX_USE_CXX11_ABI.
    [_GLIBCXX_USE_CHAR8_T] (__gnu_debug::u8string): New.
    (__gnu_debug::u16string, __gnu_debug::u32string): New.
[!_GLIBCXX_COMPATIBILITY_CXX0X](std::hash<__gnu_debug::string>): New.
[!_GLIBCXX_COMPATIBILITY_CXX0X][_GLIBCXX_USE_WCHAR_T](std::hash<__gnu_debug::wstring>): 
New.

[_GLIBCXX_USE_CHAR8_T](std::hash<__gnu_debug::u8string>): New.
    (std::hash<__gnu_debug::u16string>): New.
    (std::hash<__gnu_debug::u32string>): New.
    * testsuite/21_strings/basic_string/hash/hash_char8_t.cc: 
Adapt for

    __gnu_debug basic_string.

Tested under Linux x86_64.

Ok to commit ?

François



diff --git a/libstdc++-v3/include/debug/string 
b/libstdc++-v3/include/debug/string

index d6eb5280ade..dec23f6277b 100644
--- a/libstdc++-v3/include/debug/string
+++ b/libstdc++-v3/include/debug/string
@@ -41,6 +41,14 @@
    __gnu_debug::_Error_formatter::_S_at(_File, _Line, _Func)    \
  ._M_message(#_Cond)._M_error()

+#if _GLIBCXX_USE_CXX11_ABI && __cplusplus >= 201103
+# define _GLIBCXX_CPP11_AND_CXX11_ABI 1
+# define _GLIBCXX_CPP11_AND_CXX11_ABI_ONLY(Statement) Statement


This takes an expression, not a statement.


I've been inspired by _GLIBCXX_DEBUG_ONLY



I think it would be better to use more descriptive names for these:

# define _GLIBCXX_INSERT_RETURNS_ITERATOR 1
# define _GLIBCXX_INSERT_RETURNS_ITERATOR_ONLY(expr) expr

(And don't forget to change the #undef lines too).


+#if __cplusplus >= 201103L
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  // DR 1182.
+
+#ifndef _GLIBCXX_COMPATIBILITY_CXX0X
+  /// std::hash specialization for string.
+  template<>
+    struct hash<__gnu_debug::string>
+    : public __hash_base


I think we could just define on partial specialization that works for
all cases:


Yes, sounds better. But I relied on std::__hash_base which gives 
directly the correct definition.




Why only make this change for the char8_t version? Why not test
hash<__gnu_debug::string> as well?


This file also test std::string and so also __gnu_debug::string.

    libstdc++: Fix and complete __gnu_debug::basic_string implementation

    Fix and complete __gnu_debug::basic_string so that it can be used 
as a transparent

    replacement of std::basic_string.

    libstdc++-v3/ChangeLog:

    * include/debug/string
    (basic_string(const _CharT*, const _Allocator&)): Remove 
assign call.
    (basic_string<>::insert(const_iterator, _InputIte, 
_InputIte)): Try to

    remove iterator debug layer even if !_GLIBCXX_USE_CXX11_ABI.
    [_GLIBCXX_USE_CHAR8_T] (__gnu_debug::u8string): New.
    (__gnu_debug::u16string, __gnu_debug::u32string): New.
    (std::hash<__gnu_debug::basic_string<>>): New partial 
specialization.

(std::__is_fast_hash<__gnu_debug::basic_string<>>): Likewise.
    (basic_string(const basic_string&, const _Alloc&)): Define 
even if !_GLIBCXX_USE_CXX11_ABI.
    (basic_string(basic_string&&, const _Alloc&)): Likewise and 
add noexcept qualification.

    (basic_string<>::erase): Adapt to take __const_iterator.
    * testsuite/21_strings/basic_string/hash/debug.cc: New test.
    * testsuite/21_strings/basic_string/hash/debug_char8_t.cc: 
New test.
    * 
testsuite/21_strings/basic_string/requirements/citerators.cc: Adapt to 
test __gnu_debug::string

    when _GLIBCXX_DEBUG is defined.
    * 
testsuite/21_strings/basic_string/requirements/dr438/constructor.cc: 
Likewise.
    * 
testsuite/21_strings/basic_string/requirements/exception/basic.cc: Likewise.
    * 
testsuite/21_strings/basic_string/requirements/exception/generation_prohibited.cc: 
Likewise.
    * 
testsuite/21_strings/basic_string/requirements/exception/propagation_consistent.cc: 
Likewise.
    * 
testsuite/21_strings/basic_string/requirements/explicit_instantiation/char/1.cc: 
Likewise.