Re: [PATCH] PR fortran/90290 -- Check F2008 STOP code

2019-05-01 Thread Janne Blomqvist
On Thu, May 2, 2019 at 9:02 AM Steve Kargl
 wrote:
>
> The attach patch adds an additional check for the
> STOP code when -std=f2008 is used.  The patch has
> been bootstrapped and regression tested on
> x86_64-*-freebsd for trunk.  OK to commit?

Ok.


-- 
Janne Blomqvist


[PATCH] PR fortran/90166 -- Add check for module prefix

2019-05-01 Thread Steve Kargl
The attach patch adds a check that a module prefix 
occurs only in a module, submodule, or interface.

C1547 (R1526) MODULE shall appear only in the function-stmt or
   subroutine-stmt of a module subprogram or of a nonabstract
   interface body that is declared in the scoping unit of a
   module or submodule.

The patch has been bootstrapped and regression
tested on x86_64-*-freebsd.  OK to commit?

2019-04-19  Steven G. Kargl  

PR fortran/90166
* decl.c (in_module_or_interface): New function to check that the
current state is in a module, submodule, or interface.
(gfc_match_prefix): Use it.

PR fortran/90166
* gfortran.dg/submodule_22.f08: Add additional dg-error comments.

-- 
Steve
Index: gcc/fortran/decl.c
===
--- gcc/fortran/decl.c	(revision 270181)
+++ gcc/fortran/decl.c	(working copy)
@@ -6070,7 +6070,29 @@ cleanup:
   return m;
 }
 
+static bool
+in_module_or_interface(void)
+{
+  if (gfc_current_state () == COMP_MODULE
+  || gfc_current_state () == COMP_SUBMODULE 
+  || gfc_current_state () == COMP_INTERFACE)
+return true;
 
+  if (gfc_state_stack->state == COMP_CONTAINS
+  || gfc_state_stack->state == COMP_FUNCTION
+  || gfc_state_stack->state == COMP_SUBROUTINE)
+{
+  gfc_state_data *p;
+  for (p = gfc_state_stack->previous; p ; p = p->previous)
+	{
+	  if (p->state == COMP_MODULE || p->state == COMP_SUBMODULE 
+	  || p->state == COMP_INTERFACE)
+	return true;
+	}
+}
+return false;
+}
+
 /* Match a prefix associated with a function or subroutine
declaration.  If the typespec pointer is nonnull, then a typespec
can be matched.  Note that if nothing matches, MATCH_YES is
@@ -6102,6 +6124,13 @@ gfc_match_prefix (gfc_typespec *ts)
 	{
 	  if (!gfc_notify_std (GFC_STD_F2008, "MODULE prefix at %C"))
 	goto error;
+
+	  if (!in_module_or_interface ())
+	{
+	  gfc_error ("MODULE prefix at %C found outside of a module, "
+			 "submodule, or INTERFACE");
+	  goto error;
+	}
 
 	  current_attr.module_procedure = 1;
 	  found_prefix = true;
Index: gcc/testsuite/gfortran.dg/submodule_22.f08
===
--- gcc/testsuite/gfortran.dg/submodule_22.f08	(revision 270181)
+++ gcc/testsuite/gfortran.dg/submodule_22.f08	(working copy)
@@ -40,8 +40,10 @@ end
 
 submodule (mtop:submod:subsubmod) subsubsubmod ! { dg-error "Syntax error in SUBMODULE statement" }
 contains
-  module subroutine sub3
-r = 2.0
-s = 2.0
-  end subroutine sub3
+  module subroutine sub3  ! { dg-error "found outside of a module" }
+r = 2.0   ! { dg-error "Unexpected assignment" }
+s = 2.0   ! { dg-error "Unexpected assignment" }
+  end subroutine sub3 ! { dg-error "Expecting END PROGRAM statement" }
 end
+
+found outside of a module


[PATCH] PR fortran/90290 -- Check F2008 STOP code

2019-05-01 Thread Steve Kargl
The attach patch adds an additional check for the
STOP code when -std=f2008 is used.  The patch has
been bootstrapped and regression tested on 
x86_64-*-freebsd for trunk.  OK to commit?

2019-05-01  Steven G. Kargl  

PR fortran/90290
* match.c (gfc_match_stopcode): Check F2008 condition on stop code.

2019-05-01  Steven G. Kargl  

PR fortran/90290
* gfortran.dg/pr90290.f90: New test.

-- 
Steve
Index: gcc/fortran/match.c
===
--- gcc/fortran/match.c	(revision 270774)
+++ gcc/fortran/match.c	(working copy)
@@ -2955,7 +2955,7 @@ gfc_match_stopcode (gfc_statement st)
 {
   gfc_expr *e = NULL;
   match m;
-  bool f95, f03;
+  bool f95, f03, f08;
 
   /* Set f95 for -std=f95.  */
   f95 = (gfc_option.allow_std == GFC_STD_OPT_F95);
@@ -2963,6 +2963,9 @@ gfc_match_stopcode (gfc_statement st)
   /* Set f03 for -std=f2003.  */
   f03 = (gfc_option.allow_std == GFC_STD_OPT_F03);
 
+  /* Set f08 for -std=f2008.  */
+  f08 = (gfc_option.allow_std == GFC_STD_OPT_F08);
+
   /* Look for a blank between STOP and the stop-code for F2008 or later.  */
   if (gfc_current_form != FORM_FIXED && !(f95 || f03))
 {
@@ -3051,8 +3054,8 @@ gfc_match_stopcode (gfc_statement st)
   /* Test for F95 and F2003 style STOP stop-code.  */
   if (e->expr_type != EXPR_CONSTANT && (f95 || f03))
 	{
-	  gfc_error ("STOP code at %L must be a scalar CHARACTER constant or "
-		 "digit[digit[digit[digit[digit", &e->where);
+	  gfc_error ("STOP code at %L must be a scalar CHARACTER constant "
+		 "or digit[digit[digit[digit[digit", &e->where);
 	  goto cleanup;
 	}
 
@@ -3061,6 +3064,14 @@ gfc_match_stopcode (gfc_statement st)
   gfc_init_expr_flag = true;
   gfc_reduce_init_expr (e);
   gfc_init_expr_flag = false;
+
+  /* Test for F2008 style STOP stop-code.  */
+  if (e->expr_type != EXPR_CONSTANT && f08)
+	{
+	  gfc_error ("STOP code at %L must be a scalar default CHARACTER or "
+		 "INTEGER constant expression", &e->where);
+	  goto cleanup;
+	}
 
   if (!(e->ts.type == BT_CHARACTER || e->ts.type == BT_INTEGER))
 	{
Index: gcc/testsuite/gfortran.dg/pr90290.f90
===
--- gcc/testsuite/gfortran.dg/pr90290.f90	(nonexistent)
+++ gcc/testsuite/gfortran.dg/pr90290.f90	(working copy)
@@ -0,0 +1,7 @@
+! { dg-do compile }
+! { dg-options "-std=f2008" }
+program errorstop
+  integer :: ec
+  read *, ec
+  stop ec  ! { dg-error "STOP code at " }
+end program


[PATCH] libphobos: RISC-V: Fix soft-float build errors with IEEE exception flags

2019-05-01 Thread Maciej Rozycki
From: Maciej W. Rozycki 

Fix assembly errors:

.../libphobos/src/std/math.d: Assembler 
messages:.../libphobos/src/std/math.d:4773: Error: unrecognized opcode `frflags 
a0'
.../libphobos/src/std/math.d:4856: Error: unrecognized opcode `fsflags a5'
.../libphobos/src/std/math.d:4856: Error: unrecognized opcode `fsflags a5'
.../libphobos/src/std/math.d:4773: Error: unrecognized opcode `frflags a0'
.../libphobos/src/std/math.d:5549: Error: unrecognized opcode `fscsr a5'
.../libphobos/src/std/math.d:5456: Error: unrecognized opcode `frcsr a5'
.../libphobos/src/std/math.d:5456: Error: unrecognized opcode `frcsr a5'
.../libphobos/src/std/math.d:5549: Error: unrecognized opcode `fscsr a5'
.../libphobos/src/std/math.d:5456: Error: unrecognized opcode `frcsr a5'
.../libphobos/src/std/math.d:5549: Error: unrecognized opcode `fscsr a0'
.../libphobos/src/std/math.d:5456: Error: unrecognized opcode `frcsr a0'
.../libphobos/src/std/math.d:5456: Error: unrecognized opcode `frcsr a0'
.../libphobos/src/std/math.d:5549: Error: unrecognized opcode `fscsr s2'
make[8]: *** [Makefile:1119: std/math.lo] Error 1

triggered with the RISC-V lp64 multilib in a GCC build configured with 
`--enable-multilib --enable-languages=all --target=riscv64-linux-gnu'. 
This is due to unconditional explicit use of F extension instructions 
within inline assembly, to access IEEE exception flags.  The use of 
these instructions is not allowed when building for a soft-float ABI.

Correct the problem by wrapping said inline assembly into a conditional 
such that if `D_SoftFloat' is true, then reads from IEEE exception flags 
return 0 and writes are ignored instead, complementing r270522 
("libphobos: Add D support for RISC-V Linux"), which is an updated 
version of , 
where the problematic code has originated from.

libphobos/
* std/math.d (IeeeFlags.getIeeeFlags): Handle RISC-V soft-float
ABI.
(IeeeFlags.resetIeeeFlags): Likewise.
(FloatingPointControl.getControlState): Likewise.
(FloatingPointControl.setControlState): Likewise.
---
Hi,

 I believe this change is obviously correct, and I also verified generated 
code using `objdump -d'.  I have no way to regression-test it right now.

 Please confirm if I correctly referred to identifiers in the ChangeLog 
entry though, as my experience WRT the D programming language and its 
syntax in particular is nil.

 My understanding is changes to `libphobos' are supposed to go upstream 
first, but r270522 is a local change anyway AFAICT, and technically a 
`--enable-languages=all' build regression, so we better fix it ASAP.

 Finally my WDC copyright assignment with FSF is still in the works, but I 
believe this change can be considered legally insignificant for copyright 
purposes, i.e. having at most 15 lines or so, unless adding white space 
for indentation counts against that limit as well (which I doubt).

 With all of the above in mind, OK to apply to trunk and to GCC 9?

  Maciej
---
 libphobos/src/std/math.d |   46 +-
 1 file changed, 33 insertions(+), 13 deletions(-)

gcc-riscv-libphobos-soft-float.diff
Index: gcc/libphobos/src/std/math.d
===
--- gcc.orig/libphobos/src/std/math.d
+++ gcc/libphobos/src/std/math.d
@@ -4767,12 +4767,17 @@ struct IeeeFlags
 }
 else version (RISCV_Any)
 {
-uint result = void;
-asm pure nothrow @nogc
+version (D_SoftFloat)
+return 0;
+else
 {
-"frflags %0" : "=r" result;
+uint result = void;
+asm pure nothrow @nogc
+{
+"frflags %0" : "=r" result;
+}
+return result;
 }
-return result;
 }
 else
 assert(0, "Not yet supported");
@@ -4850,10 +4855,15 @@ struct IeeeFlags
 }
 else version (RISCV_Any)
 {
-uint newValues = 0x0;
-asm pure nothrow @nogc
+version (D_SoftFloat)
+return;
+else
 {
-"fsflags %0" : : "r" newValues;
+uint newValues = 0x0;
+asm pure nothrow @nogc
+{
+"fsflags %0" : : "r" newValues;
+}
 }
 }
 else
@@ -5450,12 +5460,17 @@ struct FloatingPointControl
 }
 else version (RISCV_Any)
 {
-ControlState cont;
-asm pure nothrow @nogc
+version (D_SoftFloat)
+return 0;
+else
 {
- 

Re: [patch, fortran] Fix PR 61968

2019-05-01 Thread Dominique d'Humières
Hi Thomas,

> …
> This also clears the ICE for my inline packing patch which
> was reported by Dominique.
> …

Not for me, I still get

% gfc pr61968.f90 -c -O3
pr61968.f90:32:0:

   32 | call test_lib (a, int (sizeof (a), kind=c_size_t))
  | 
internal compiler error: in gfc_trans_create_temp_array, at 
fortran/trans-array.c:1265

TIA

Dominique



Go patch committed: Recognize and optimize map range clear

2019-05-01 Thread Ian Lance Taylor
This patch by Cherry Zhang tweaks the Go frontend to recognize and
optimize map range clear.  When we see

for k := range m { delete(m, k) }

for map m, we rewrite it to runtime.mapclear, as the gc compiler does.
Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.  Committed
to mainline.

Ian
Index: gcc/go/gofrontend/MERGE
===
--- gcc/go/gofrontend/MERGE (revision 270779)
+++ gcc/go/gofrontend/MERGE (working copy)
@@ -1,4 +1,4 @@
-b42744825e3f2d1d2981eedbb67d6ac6419b8122
+7e590184ae1ebc02e1b2577de00cf4fe842217dc
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: gcc/go/gofrontend/runtime.def
===
--- gcc/go/gofrontend/runtime.def   (revision 270552)
+++ gcc/go/gofrontend/runtime.def   (working copy)
@@ -137,6 +137,9 @@ DEF_GO_RUNTIME(MAPITERINIT, "runtime.map
 // Range over a map, moving to the next map entry.
 DEF_GO_RUNTIME(MAPITERNEXT, "runtime.mapiternext", P1(POINTER), R0())
 
+// Clear a map.
+DEF_GO_RUNTIME(MAPCLEAR, "runtime.mapclear", P2(TYPE, MAP), R0())
+
 
 // Make a channel.
 DEF_GO_RUNTIME(MAKECHAN, "runtime.makechan", P2(TYPE, INT), R1(CHAN))
Index: gcc/go/gofrontend/statements.cc
===
--- gcc/go/gofrontend/statements.cc (revision 270552)
+++ gcc/go/gofrontend/statements.cc (working copy)
@@ -5485,6 +5485,7 @@ For_range_statement::do_lower(Gogo* gogo
   Location loc = this->location();
   Block* temp_block = new Block(enclosing, loc);
 
+  Expression* orig_range_expr = this->range_;
   Named_object* range_object = NULL;
   Temporary_statement* range_temp = NULL;
   if (eval)
@@ -5500,6 +5501,22 @@ For_range_statement::do_lower(Gogo* gogo
}
 }
 
+  // Try to match "range clear" patterns and rewrite to simple runtime
+  // calls.
+  if (range_type->map_type() != NULL)
+{
+  Statement* clear = this->lower_map_range_clear(range_type,
+ enclosing,
+ orig_range_expr,
+ range_object,
+ range_temp, loc);
+  if (clear != NULL)
+{
+  temp_block->add_statement(clear);
+  return Statement::make_block_statement(temp_block, loc);
+}
+}
+
   Temporary_statement* index_temp = Statement::make_temporary(index_type,
  NULL, loc);
   temp_block->add_statement(index_temp);
@@ -6141,6 +6158,85 @@ For_range_statement::lower_range_channel
   *piter_init = iter_init;
 }
 
+// Match
+//
+//   for k := range m { delete(m, k) }
+//
+// Lower it to runtime.mapclear(TYPE, m) on match, return the statement
+// containing the call.  Return NULL otherwise.
+
+Statement*
+For_range_statement::lower_map_range_clear(Type* map_type,
+   Block* enclosing,
+   Expression* orig_range_expr,
+   Named_object* range_object,
+   Temporary_statement* range_temp,
+   Location loc)
+{
+  if (this->value_var_ != NULL)
+return NULL;
+  if (this->index_var_ == NULL)
+return NULL;
+
+  // Require the loop index be a new variable.  We cannot rewrite
+  // if it is used outside of the loop.
+  Var_expression* index_ve = this->index_var_->var_expression();
+  if (index_ve == NULL)
+return NULL;
+  Named_object* index_no = index_ve->named_object();
+  if (enclosing->bindings()->lookup_local(index_no->name()) != index_no)
+return NULL;
+
+  // Match the body.  When lowering the builtin delete function, we have
+  // inserted temporaries, so we actually match for
+  //
+  //   tmp1 = m
+  //   tmp2 = k
+  //   runtime.mapdelete(TYPE, tmp1, &tmp2)
+
+  const std::vector* statements = this->statements_->statements();
+  if (statements->size() != 3)
+return NULL;
+
+  Temporary_statement* ts1 = statements->at(0)->temporary_statement();
+  Temporary_statement* ts2 = statements->at(1)->temporary_statement();
+  Expression_statement* es3 = statements->at(2)->expression_statement();
+  if (ts1 == NULL || ts2 == NULL || es3 == NULL
+  || !Expression::is_same_variable(orig_range_expr, ts1->init())
+  || !Expression::is_same_variable(this->index_var_, ts2->init()))
+return NULL;
+  Call_expression* call = es3->expr()->call_expression();
+  if (call == NULL)
+return NULL;
+  Func_expression* fe = call->fn()->func_expression();
+  if (fe == NULL || !fe->is_runtime_function()
+  || fe->runtime_code() != Runtime::MAPDELETE)
+return NULL;
+  Expression* a1 = call->args()->at(1);
+  a1 = (a1->unsafe_conversion_expr

Go patch committed: use more direct interfaces

2019-05-01 Thread Ian Lance Taylor
This patch by Cherry Zhang changes the Go frontend and libgo to use
more direct interfaces.  A direct interface is an interface whose data
word contains the actual data value, instead of a pointer to it. The
gc toolchain creates a direct interface if the value is pointer
shaped, that includes pointers (including unsafe.Pointer), functions,
channels, maps, and structs and arrays containing a single
pointer-shaped field. In gccgo, we only do this for pointers. This
patch unifies direct interface types with gc. This reduces allocations
when converting such types to interfaces.

Our method functions used to always take pointer receivers, to make
interface calls easy. Now for direct interface types, their value
methods will take value receivers. For a pointer to those types, when
converted to interface, the interface data contains the pointer. For
that interface to call a value method, it will need a wrapper method
that dereference the pointer and invokes the value method. The wrapper
method, instead of the actual one, is put into the itable of the
pointer type.

In the runtime, adjust funcPC for the new layout of interfaces of functions.

Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.  Committed
to mainline.

Ian
Index: gcc/go/gofrontend/MERGE
===
--- gcc/go/gofrontend/MERGE (revision 270778)
+++ gcc/go/gofrontend/MERGE (working copy)
@@ -1,4 +1,4 @@
-e0b906b13cbc947406c634aaf8b06270292bd7e0
+b42744825e3f2d1d2981eedbb67d6ac6419b8122
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: gcc/go/gofrontend/expressions.cc
===
--- gcc/go/gofrontend/expressions.cc(revision 270552)
+++ gcc/go/gofrontend/expressions.cc(working copy)
@@ -292,11 +292,11 @@ Expression::convert_type_to_interface(Ty
 }
 
   Expression* obj;
-  if (rhs_type->points_to() != NULL)
+  if (rhs_type->is_direct_iface_type())
 {
   // We are assigning a pointer to the interface; the interface
   // holds the pointer itself.
-  obj = rhs;
+  obj = unpack_direct_iface(rhs, location);
 }
   else
 {
@@ -310,6 +310,60 @@ Expression::convert_type_to_interface(Ty
   return Expression::make_interface_value(lhs_type, first_field, obj, 
location);
 }
 
+// Return an expression for the pointer-typed value of a direct interface
+// type.  Specifically, for single field struct or array, get the single
+// field, and do this recursively.  The reason for this is that we don't
+// want to assign a struct or an array to a pointer-typed field.  The
+// backend may not like that.
+
+Expression*
+Expression::unpack_direct_iface(Expression* rhs, Location loc)
+{
+  Struct_type* st = rhs->type()->struct_type();
+  if (st != NULL)
+{
+  go_assert(st->field_count() == 1);
+  Expression* field = Expression::make_field_reference(rhs, 0, loc);
+  return unpack_direct_iface(field, loc);
+}
+  Array_type* at = rhs->type()->array_type();
+  if (at != NULL)
+{
+  int64_t len;
+  bool ok = at->int_length(&len);
+  go_assert(ok && len == 1);
+  Type* int_type = Type::lookup_integer_type("int");
+  Expression* index = Expression::make_integer_ul(0, int_type, loc);
+  Expression* elem = Expression::make_array_index(rhs, index, NULL, NULL, 
loc);
+  return unpack_direct_iface(elem, loc);
+}
+  return rhs;
+}
+
+// The opposite of unpack_direct_iface.
+
+Expression*
+Expression::pack_direct_iface(Type* t, Expression* rhs, Location loc)
+{
+  if (rhs->type() == t)
+return rhs;
+  Struct_type* st = t->struct_type();
+  if (st != NULL)
+{
+  Expression_list* vals = new Expression_list();
+  vals->push_back(pack_direct_iface(st->field(0)->type(), rhs, loc));
+  return Expression::make_struct_composite_literal(t, vals, loc);
+}
+  Array_type* at = t->array_type();
+  if (at != NULL)
+{
+  Expression_list* vals = new Expression_list();
+  vals->push_back(pack_direct_iface(at->element_type(), rhs, loc));
+  return Expression::make_array_composite_literal(t, vals, loc);
+}
+  return Expression::make_unsafe_cast(t, rhs, loc);
+}
+
 // Return an expression for the type descriptor of RHS.
 
 Expression*
@@ -426,9 +480,11 @@ Expression::convert_interface_to_type(Ty
   Expression* obj = Expression::make_interface_info(rhs, INTERFACE_INFO_OBJECT,
 location);
 
-  // If the value is a pointer, then it is the value we want.
+  // If the value is a direct interface, then it is the value we want.
   // Otherwise it points to the value.
-  if (lhs_type->points_to() == NULL)
+  if (lhs_type->is_direct_iface_type())
+obj = Expression::pack_direct_iface(lhs_type, obj, location);
+  else
 {
   obj = Expression::make_unsafe_cast(Type::make_pointer_type(lhs_type), 
obj,
 

[patch, fortran] Fix PR 61968

2019-05-01 Thread Thomas Koenig

Hello world,

the attached patch fixes an error where TYPE(*) ended up in a vtab,
with not-so delectable results.  The solultion is simple - do not
create a vtab if the actual argument is TYPE(*).

This also clears the ICE for my inline packing patch which
was reported by Dominique.

Regression-tested. OK for trunk?

Regards

Thomas
Index: interface.c
===
--- interface.c	(Revision 270622)
+++ interface.c	(Arbeitskopie)
@@ -2989,7 +2989,8 @@ compare_actual_formal (gfc_actual_arglist **ap, gf
 	 polymorphic formal arguments.  */
   if (UNLIMITED_POLY (f->sym)
 	  && a->expr->ts.type != BT_DERIVED
-	  && a->expr->ts.type != BT_CLASS)
+	  && a->expr->ts.type != BT_CLASS
+	  && a->expr->ts.type != BT_ASSUMED)
 	gfc_find_vtab (&a->expr->ts);
 
   if (a->expr->expr_type == EXPR_NULL
! { dg-do compile }
! { dg-options "-O0 -fdump-tree-original" }
! PR 61968 - this used to generate invalid assembler containing
! TYPE(*).

module testmod
  use iso_c_binding, only: c_size_t, c_int32_t, c_int64_t
  implicit none

  interface test
procedure :: test_32
procedure :: test_array
  end interface test

  interface
subroutine test_lib (a, len) bind(C, name="xxx")
  use iso_c_binding, only: c_size_t
  type(*), dimension(*) :: a
  integer(c_size_t), value :: len
   end subroutine
  end interface

contains

  subroutine test_32 (a, len)
type(*), dimension(*) :: a
integer(c_int32_t), value :: len
call test_lib (a, int (len, kind=c_size_t))
  end subroutine

  subroutine test_array (a)
use iso_c_binding, only: c_size_t
class(*), dimension(..), target :: a
call test_lib (a, int (sizeof (a), kind=c_size_t))
  end subroutine

end module

  subroutine test_32_ (a, len)
use iso_c_binding, only: c_int32_t
use testmod
type(*), dimension(*) :: a
integer(c_int32_t), value :: len
call test (a, len)
  end subroutine
! { dg-final { scan-tree-dump-not "! __vtype_TYPE\\(*\\)" "original" } }


libgo patch committed: persistent interface table cache

2019-05-01 Thread Ian Lance Taylor
This libgo patch by Cherry Zhang adds a persistent interface table cache.

Previously, each time we do an interface conversion for which the
method table is not known at compile time, we allocate a new method
table.

This patch ports the mechanism of itab caching from the gc runtime,
adapted to our itab representation and method finding mechanism.  With
the cache, we reuse the same itab for the same (interface, concrete)
type pair. This reduces allocations in interface conversions.

Unlike the gc runtime, we don't prepopulate the cache with statically
allocated itabs, as currently we don't have a way to find them. This
means we don't deduplicate run-time allocated itabs with compile-time
allocated ones. But that is not too bad -- it is just a cache anyway.

Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.  Committed
to mainline.

Ian
Index: gcc/go/gofrontend/MERGE
===
--- gcc/go/gofrontend/MERGE (revision 270658)
+++ gcc/go/gofrontend/MERGE (working copy)
@@ -1,4 +1,4 @@
-9476f6183791477dd9b883f51e2a46b224227735
+e0b906b13cbc947406c634aaf8b06270292bd7e0
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: libgo/go/runtime/iface.go
===
--- libgo/go/runtime/iface.go   (revision 270552)
+++ libgo/go/runtime/iface.go   (working copy)
@@ -5,6 +5,8 @@
 package runtime
 
 import (
+   "runtime/internal/atomic"
+   "runtime/internal/sys"
"unsafe"
 )
 
@@ -73,47 +75,160 @@ import (
 
 // For a nil interface value both fields in the interface struct are nil.
 
-// Return the interface method table for a value of type rhs converted
-// to an interface of type lhs.
-func getitab(lhs, rhs *_type, canfail bool) unsafe.Pointer {
-   if rhs == nil {
-   return nil
-   }
+// itabs are statically allocated or persistently allocated. They are
+// never freed. For itabs allocated at run time, they are cached in
+// itabTable, so we reuse the same itab for the same (interface, concrete)
+// type pair. The gc runtime prepopulates the cache with statically
+// allocated itabs. Currently we don't do that as we don't have a way to
+// find all the statically allocated itabs.
+
+const itabInitSize = 512
+
+var (
+   itabLock  mutex   // lock for accessing 
itab table
+   itabTable = &itabTableInit// pointer to current 
table
+   itabTableInit = itabTableType{size: itabInitSize} // starter table
+)
 
-   if lhs.kind&kindMask != kindInterface {
-   throw("getitab called for non-interface type")
+// Cache entry type of itab table.
+// For gccgo, this is not the data type we used in the interface header.
+type itab struct {
+   inter   *interfacetype
+   methods [2]unsafe.Pointer // method table. variable sized. first entry 
is the type descriptor.
+}
+
+func (m *itab) _type() *_type {
+   return (*_type)(m.methods[0])
+}
+
+// Note: change the formula in the mallocgc call in itabAdd if you change 
these fields.
+type itabTableType struct {
+   sizeuintptr // length of entries array. Always a power 
of 2.
+   count   uintptr // current number of filled entries.
+   entries [itabInitSize]*itab // really [size] large
+}
+
+func itabHashFunc(inter *interfacetype, typ *_type) uintptr {
+   // compiler has provided some good hash codes for us.
+   return uintptr(inter.typ.hash ^ typ.hash)
+}
+
+// find finds the given interface/type pair in t.
+// Returns nil if the given interface/type pair isn't present.
+func (t *itabTableType) find(inter *interfacetype, typ *_type) *itab {
+   // Implemented using quadratic probing.
+   // Probe sequence is h(i) = h0 + i*(i+1)/2 mod 2^k.
+   // We're guaranteed to hit all table entries using this probe sequence.
+   mask := t.size - 1
+   h := itabHashFunc(inter, typ) & mask
+   for i := uintptr(1); ; i++ {
+   p := (**itab)(add(unsafe.Pointer(&t.entries), h*sys.PtrSize))
+   // Use atomic read here so if we see m != nil, we also see
+   // the initializations of the fields of m.
+   // m := *p
+   m := (*itab)(atomic.Loadp(unsafe.Pointer(p)))
+   if m == nil {
+   return nil
+   }
+   if m.inter == inter && m._type() == typ {
+   return m
+   }
+   h += i
+   h &= mask
}
+}
 
-   lhsi := (*interfacetype)(unsafe.Pointer(lhs))
+// itabAdd adds the given itab to the itab hash table.
+// itabLock must be held.
+func itabAdd(m *itab) {
+   // Bugs can lead to calling this while mallocing is set,
+   // typically because this is called while panicing.
+   // Crash reliably, rather than only when we need 

Re: module_column not initialized in write_module()

2019-05-01 Thread Andrew Benson
Thanks Thomas, committed as r270777.

On Wednesday, May 1, 2019 9:35:13 PM PDT Thomas Koenig wrote:
> Hi Andrew,
> 
> > Fixing this seems to be simple:
> > 
> > --- gcc/fortran/module.c(revision 270772)
> > +++ gcc/fortran/module.c(working copy)
> > @@ -6052,6 +6052,9 @@ write_module (void)
> > 
> >   {
> >   
> > int i;
> > 
> > +  /* Initialize the column counter. */
> > +  module_column = 1;
> > +
> > 
> > /* Write the operator interfaces.  */
> > mio_lparen ();
> > 
> > This causes no regressions. I've attached the patch including the
> > ChangeLog - is this ok to commit?
> 
> OK for trunk.
> 
> Thanks a lot for the patch!
> 
> Regards
> 
>   Thomas


-- 

* Andrew Benson: http://users.obs.carnegiescience.edu/abenson/contact.html

* Galacticus: https://bitbucket.org/galacticusdev/galacticus



Re: module_column not initialized in write_module()

2019-05-01 Thread Thomas Koenig

Hi Andrew,


Fixing this seems to be simple:

--- gcc/fortran/module.c(revision 270772)
+++ gcc/fortran/module.c(working copy)
@@ -6052,6 +6052,9 @@ write_module (void)
  {
int i;
  
+  /* Initialize the column counter. */

+  module_column = 1;
+
/* Write the operator interfaces.  */
mio_lparen ();

This causes no regressions. I've attached the patch including the ChangeLog -
is this ok to commit?


OK for trunk.

Thanks a lot for the patch!

Regards

Thomas


module_column not initialized in write_module()

2019-05-01 Thread Andrew Benson
The value of 'module_column' is not initialized in write_module() before a 
module file is written. As a result, the first line break in the module file 
can 
occur at an arbitrary column, depending on what value 'module_column' happens 
to have. While this doesn't affect the behavior of the module file as far as 
gfortran is concerned, it does mean that the structure of the module file can 
change, even though the actual content is unaltered. 

For example, these first few lines of a (uncompressed) module file before and 
after adding a single write statement to one of its functions:

GFORTRAN module version '15' created from 
structure_formation.excursion_sets.first_crossing_distribution.p.F90
(() ()
() () () () () () () () () () () () () () () () () () () () () () () ()
())

()

and:

GFORTRAN module version '15' created from 
structure_formation.excursion_sets.first_crossing_distribution.p.F90
(() () () () () () () () () () () () () () () () () () () () () () ()
() () () ())

()

When building large projects with gfortran I 'cmp' newly produced module files 
with the equivalent module file from the previous build as a way to avoid 
recompilation cascades. The changing position of the first line break makes 
this approach not work.

Fixing this seems to be simple:

--- gcc/fortran/module.c(revision 270772)
+++ gcc/fortran/module.c(working copy)
@@ -6052,6 +6052,9 @@ write_module (void)
 {
   int i;
 
+  /* Initialize the column counter. */
+  module_column = 1;
+
   /* Write the operator interfaces.  */
   mio_lparen ();

This causes no regressions. I've attached the patch including the ChangeLog - 
is this ok to commit?

-AndrewIndex: gcc/fortran/ChangeLog
===
--- gcc/fortran/ChangeLog	(revision 270772)
+++ gcc/fortran/ChangeLog	(working copy)
@@ -1,3 +1,8 @@
+2019-05-01  Andrew Benson  
+
+	* module.c (write_module): Initialize module_column before writing
+	module to ensure line break occurs at correct column.
+
 2019-04-19  Steven G. Kargl  
 
 	PR fortran/90166
Index: gcc/fortran/module.c
===
--- gcc/fortran/module.c	(revision 270772)
+++ gcc/fortran/module.c	(working copy)
@@ -6052,6 +6052,9 @@ write_module (void)
 {
   int i;
 
+  /* Initialize the column counter. */
+  module_column = 1;
+  
   /* Write the operator interfaces.  */
   mio_lparen ();
 


[committed] [PR tree-optimization/88797] Thottle back path splitting in another case where it'll inhibit if-conversion

2019-05-01 Thread Jeff Law

This fixes pr88797 by avoiding path splitting when we've got a
candidate, but the PHI feeds a conditional in the join block.  ie:

  # iftmp.0_11 = PHI <(3), 1112(4)>
[ ... ]
  _14 = iftmp.0_11 > x_17;


These are more likely going to be if-conversion candidates and
if-conversion is generally more profitable than path splitting.

This doesn't feel terribly important to fix for gcc-9, so I'm just
installing on the trunk.  But backporting would be trivial and safe if
someone feels it's important enough to do so.

This has been bootstrapped and regression tested on a variety of native
targets, it's also been tested to a lesser degree on the various *-elf
targets.

Installing on the trunk momentarily.

jeff
* gimple-ssa-split-paths (is_feasible_trace): Reject cases where the
PHI feeds a conditional on the RHS of an assignment.

* g++.dg/tree-ssa/pr88797.C: New test.

diff --git a/gcc/gimple-ssa-split-paths.c b/gcc/gimple-ssa-split-paths.c
index 33bbb66674b..5bf45eeac28 100644
--- a/gcc/gimple-ssa-split-paths.c
+++ b/gcc/gimple-ssa-split-paths.c
@@ -264,8 +264,12 @@ is_feasible_trace (basic_block bb)
  if (is_gimple_debug (stmt))
continue;
  /* If there's a use in the joiner this might be a CSE/DCE
-opportunity.  */
- if (gimple_bb (stmt) == bb)
+opportunity, but not if the use is in a conditional
+which makes this a likely if-conversion candidate.  */
+ if (gimple_bb (stmt) == bb
+ && (!is_gimple_assign (stmt)
+ || (TREE_CODE_CLASS (gimple_assign_rhs_code (stmt))
+ != tcc_comparison)))
{
  found_useful_phi = true;
  break;
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr88797.C 
b/gcc/testsuite/g++.dg/tree-ssa/pr88797.C
new file mode 100644
index 000..75391d6c049
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr88797.C
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fdump-tree-split-paths-details" } */
+
+
+void use(unsigned);
+bool f(unsigned x, unsigned y) {
+return x <  + (y <= );
+}
+void test_f(unsigned x, unsigned y) {
+for (unsigned i = 0; i < ; ++i)
+use(f(x++, y++));
+}
+
+/* { dg-final { scan-tree-dump-not "Duplicating join block" "split-paths" } } 
*/
+/* { dg-final { scan-tree-dump-times "Block . is a join that does not expose" 
1 "split-paths" } } */
+


Re: [v3] Update Solaris baselines for GCC 9.1

2019-05-01 Thread Rainer Orth
Hi Jakub,

> On Fri, Apr 26, 2019 at 12:11:55PM +0100, Jonathan Wakely wrote:
>> On 26/04/19 09:58 +0200, Rainer Orth wrote:
>> > It recently occured to me that almost none of the libstdc++ abi
>> > baselines have been updated for the GCC 9 release.  The following patch
>> > corrects this for Solaris.  The baselines were generated on the affected
>> > releases with make new-abi-baseline.  Given that they only contain
>> > additions for versions GLIBCXX_3.4.26 and CXXABI_1.3.12, they seem
>> > sensible.
>> > 
>> > Full bootstraps across the whole range ({i386,amd64}-pc-solaris2.1[01],
>> > sparc{,v9}-sun-solaris2.1[01]) just running on both mainline and the
>> > gcc-9 branch.
>> > 
>> > Ok for mainline and gcc-9 branch if they pass?
>> 
>> OK for trunk.
>> OK for gcc-9-branch assuming Jakub acks it too.
>
> Yes.

I've now returned from vacation.  Testing has completed successfully
meanwhile, so I've installed the patch on both mainline and gcc-9
branch.

Thanks.
Rainer

-- 
-
Rainer Orth, Center for Biotechnology, Bielefeld University


Re: [PATCH][GCC 10][RFC] Fix PR testsuite/90113

2019-05-01 Thread Thomas Koenig

Hi Roman,

FAIL: gfortran.dg/inline_matmul_1.f90 scan-tree-dump-times optimized
"_gfortran_matmul" 0


With matmul, there are three versions you can get: The library version
(called as _gfortran_matmul), the inline version or a direct call
to the corresponding BLAS routine.  Which one is called, and
if there is a run-time selection between them, depends on -O and
some other options.

You'll need to look at the test case in detail.

Regards

Thomas


Re: [PATCH, rs6000] PR89765: Multiple problems with vec-insert implementation on PowerPC

2019-05-01 Thread Segher Boessenkool
On Tue, Apr 30, 2019 at 11:04:10AM -0500, Kelvin Nilsen wrote:
> 
> In combination with a related recently committed patch 
> (https://gcc.gnu.org/ml/gcc-patches/2019-04/msg00989.html), the attached 
> patch resolves the issues described in this problem report.  This patch also 
> includes tests to exercise the previously committed patch.
> 
> This patch includes redundant content from patch PR89424 
> (https://gcc.gnu.org/ml/gcc-patches/2019-04/msg00994.html), which has been 
> already been approved by Segher for trunk and backports to GCC 7 and 8 but is 
> awaiting GCC 9 release.
> 
> The patch has been bootstrapped and tested without regressions on 
> powerpc64le-unknown-linux-gnu (both P8 and P9) and on 
> powerpc64-unknown-linux-gnu (P7 and P8, both -m32 and -m64).
> 
> Segher: After GCC9 release, is this ok for trunk and backports to GCC 7 and 
> GCC8?

Okay for trunk.  If it tests fine everywhere, and GCC 9.1 has been released,
okay for 9, and after that, okay for 8 and 7, too.

Thanks!


Segher


Re: [PATCH] RX: Add rx-*-linux target

2019-05-01 Thread Yoshinori Sato
On Wed, 01 May 2019 00:37:56 +0900,
Jeff Law wrote:
> 
> On 4/30/19 7:55 AM, Yoshinori Sato wrote:
> > On Tue, 30 Apr 2019 06:48:01 +0900,
> > Jeff Law wrote:
> >>
> >> On 3/26/19 8:21 AM, Yoshinori Sato wrote:
> >>> I ported linux kernel to Renesas RX.
> >>>
> >>> rx-*-elf target output a binary different from the standard ELF.
> >>> It has the same format as the Renesas compiler.
> >>>
> >>> But the linux kernel requires the standard ELF format.
> >>> I want to define a rx-*-linux target so that I can generate
> >>> a standard ELF binary.I believe you have a copyright assignment on file 
> >>> for your H8 work.  Was
> >> the assignment specific to the H8 or was it more general?
> > 
> > No. This changes other target.
> > These files are not included in my copyright assignment.
> > 
> >>
> >>> diff --git a/gcc/config/rx/linux.h b/gcc/config/rx/linux.h
> >>> new file mode 100644
> >>> index 000..69500a379f2
> >>> --- /dev/null
> >>> +++ b/gcc/config/rx/linux.h
> >>
> >>> +
> >>> +/* This is how to output an element of a case-vector that is relative.
> >>> +   Note: The local label referenced by the "3b" below is emitted by
> >>> +   the tablejump insn.  */
> >>> +
> >>> +#undef ASM_OUTPUT_ADDR_DIFF_ELT
> >>> +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
> >>> +  fprintf (FILE, "\t.long .L%d - 1b\n", VALUE)
> >> Note the comment references "3b", but the output is "1b".
> > 
> > Oh.
> > I will update it.
> > 
> >> I don't see anything in here significantly concerning.  We just need to
> >> verify your copyright assignment status.
> > 
> > OK.
> > 
> >> Also, do you have write access to the repo?
> > 
> > I don't have write permission of svn repository.
> OK.  So let me know when the assignment is updated and I'll commit the
> changes.
> 
> If you forsee doing future work, you might consider a broader assignment
> so that we don't have to go through the assignment process for each
> contribution.
> 
> Jeff

Thank you.
When the procedure is over, post a patch that corrects the comment.

-- 
Yosinori Sato


[C++ PATCH] Simplify class member lookup

2019-05-01 Thread Nathan Sidwell
Here's another simplification I'd accumulated.  The final arg to 
get_class_binding no longer needs to be tri-valued, a simple bool will 
do.  This results in better diagnostics in one testcase.


nathan
--
Nathan Sidwell
2019-05-01  Nathan Sidwell  

	gcc/cp/
	* name-lookup.h (get_class_binding_direct): Change final arg to
	bool.
	(get_class_binding): Likewise.
	* name-lookup.c (get_class_binding_direct): Replace TYPE_OR_FNS
	arg with WANT_TYPE bool.  Simplify.
	(get_class_binding): Adjust final arg.
	* decl.c (reshape_init_class): Adjust get_class_binding calls.

	gcc/testsuite/
	* g++.dg/cpp0x/decltype9.C: Adjust expected diagnostics.

Index: gcc/cp/decl.c
===
--- gcc/cp/decl.c	(revision 270764)
+++ gcc/cp/decl.c	(working copy)
@@ -5968,12 +5968,12 @@ reshape_init_class (tree type, reshape_i
 		  tree id = DECL_NAME (d->cur->index);
 		  gcc_assert (id);
 		  gcc_checking_assert (d->cur->index
-   == get_class_binding (type, id, false));
+   == get_class_binding (type, id));
 		  field = d->cur->index;
 		}
 	}
 	  else if (TREE_CODE (d->cur->index) == IDENTIFIER_NODE)
-	field = get_class_binding (type, d->cur->index, false);
+	field = get_class_binding (type, d->cur->index);
 	  else
 	{
 	  if (complain & tf_error)
Index: gcc/cp/name-lookup.c
===
--- gcc/cp/name-lookup.c	(revision 270764)
+++ gcc/cp/name-lookup.c	(working copy)
@@ -1217,7 +1217,7 @@ search_anon_aggr (tree anon, tree name,
Use this if you do not want lazy member creation.  */
 
 tree
-get_class_binding_direct (tree klass, tree name, int type_or_fns)
+get_class_binding_direct (tree klass, tree name, bool want_type)
 {
   gcc_checking_assert (RECORD_OR_UNION_TYPE_P (klass));
 
@@ -1233,31 +1233,26 @@ get_class_binding_direct (tree klass, tr
   val = member_vec_binary_search (member_vec, lookup);
   if (!val)
 	;
-  else if (type_or_fns > 0)
-	{
-	  if (STAT_HACK_P (val))
-	val = STAT_TYPE (val);
-	  else if (!DECL_DECLARES_TYPE_P (val))
-	val = NULL_TREE;
-	}
   else if (STAT_HACK_P (val))
-	val = STAT_DECL (val);
+	val = want_type ? STAT_TYPE (val) : STAT_DECL (val);
+  else if (want_type && !DECL_DECLARES_TYPE_P (val))
+	val = NULL_TREE;
 }
   else
 {
-  if (member_vec && type_or_fns <= 0)
+  if (member_vec && !want_type)
 	val = member_vec_linear_search (member_vec, lookup);
 
-  if (type_or_fns < 0)
-	/* Don't bother looking for field.  We don't want it.  */;
-  else if (!val || (TREE_CODE (val) == OVERLOAD
-			&& OVL_DEDUP_P (val)))
+  if (!val || (TREE_CODE (val) == OVERLOAD && OVL_DEDUP_P (val)))
 	/* Dependent using declarations are a 'field', make sure we
 	   return that even if we saw an overload already.  */
-	if (tree field_val = fields_linear_search (klass, lookup,
-		   type_or_fns > 0))
-	  if (!val || TREE_CODE (field_val) == USING_DECL)
-	val = field_val;
+	if (tree field_val = fields_linear_search (klass, lookup, want_type))
+	  {
+	if (!val)
+	  val = field_val;
+	else if (TREE_CODE (field_val) == USING_DECL)
+	  val = ovl_make (field_val, val);
+	  }
 }
 
   /* Extract the conversion operators asked for, unless the general
@@ -1278,7 +1273,7 @@ get_class_binding_direct (tree klass, tr
special function creation as necessary.  */
 
 tree
-get_class_binding (tree klass, tree name, int type_or_fns)
+get_class_binding (tree klass, tree name, bool want_type)
 {
   klass = complete_type (klass);
 
@@ -1308,7 +1303,7 @@ get_class_binding (tree klass, tree name
 	}
 }
 
-  return get_class_binding_direct (klass, name, type_or_fns);
+  return get_class_binding_direct (klass, name, want_type);
 }
 
 /* Find the slot containing overloads called 'NAME'.  If there is no
Index: gcc/cp/name-lookup.h
===
--- gcc/cp/name-lookup.h	(revision 270764)
+++ gcc/cp/name-lookup.h	(working copy)
@@ -303,8 +303,8 @@ extern void do_namespace_alias (tree, tr
 extern tree do_class_using_decl (tree, tree);
 extern tree lookup_arg_dependent (tree, tree, vec *);
 extern tree search_anon_aggr (tree, tree, bool = false);
-extern tree get_class_binding_direct (tree, tree, int type_or_fns = -1);
-extern tree get_class_binding (tree, tree, int type_or_fns = -1);
+extern tree get_class_binding_direct (tree, tree, bool want_type = false);
+extern tree get_class_binding (tree, tree, bool want_type = false);
 extern tree *find_member_slot (tree klass, tree name);
 extern tree *add_member_slot (tree klass, tree name);
 extern void resort_type_member_vec (void *, void *,
Index: gcc/testsuite/g++.dg/cpp0x/decltype9.C
===
--- gcc/testsuite/g++.dg/cpp0x/decltype9.C	(revision 270764)
+++ gcc/testsuite/g++.dg/cpp0x/decltype9.C	(working copy)
@@ -2,8 +2,7 @@
 // { dg-do compile { target

Re: PING [RFA patch, Fortran] PR60144 - Misleading error message when missing "then" after "if" and "else if"

2019-05-01 Thread Dominique d'Humières
If there is no objection, I’ll commit the patch to trunk tonight.

Dominique

> Le 27 mars 2019 à 19:48, Thomas Koenig  a écrit :
> 
> Hi Dominique,
> 
>> Patch posted at https://gcc.gnu.org/ml/fortran/2019-03/msg00098.html
> 
> I think the patch is OK.  I think the patch is probably appropriate for
> stage 1 once that reopens.
> 
> Regards
> 
>   Thomas



[PATCH][AArch64] Emit TARGET_DOTPROD-specific sequence for sadv16qi

2019-05-01 Thread Kyrill Tkachov

Hi all,

Wilco pointed out that when the Dot Product instructions are available 
we can use them

to generate an even more efficient expansion for the [us]sadv16qi optab.
Instead of the current:
    uabdl2  v0.8h, v1.16b, v2.16b
    uabal   v0.8h, v1.8b, v2.8b
    uadalp  v3.4s, v0.8h

we can generate:
  (1)  mov    v4.16b, 1
  (2)  uabd    v0.16b, v1.16b, v2.16b
  (3)  udot    v3.4s, v0.16b, v4.16b

Instruction (1) can be CSEd across multiple such expansions and even 
hoisted outside of loops,
so when this sequence appears frequently back-to-back (like in x264_r) 
we essentially only have 2 instructions
per sum. Also, the UDOT instruction does the byte-to-word accumulation 
in one step, which allows us to use

the much simpler UABD instruction before it.

This makes it a shorter and lower-latency sequence overall for targets 
that support it.


I've added a helper abd_3 expander to simplify the generation 
of the [US]ABD patterns as well.

Bootstrapped and tested on aarch64-none-linux-gnu.

This gives about 0.5% improvement on 525.x264_r on Neoverse N1.

Ok for trunk?

Thanks,
Kyrill

2019-01-05  Kyrylo Tkachov 

    * config/aarch64/iterators.md (MAX_OPP): New code attr.
    * config/aarch64/aarch64-simd.md (abd_3): New define_expand.
    (*aarch64_abd_3): Rename to...
    (aarch64_abd_3): ... This.
    (sadv16qi): Add TARGET_DOTPROD expansion.

2019-01-05  Kyrylo Tkachov 

    * gcc.target/aarch64/ssadv16qi.c: Add +nodotprod to pragma.
    * gcc.target/aarch64/usadv16qi.c: Likewise.
    * gcc.target/aarch64/ssadv16qi-dotprod.c: New test.
    * gcc.target/aarch64/usadv16qi-dotprod.c: Likewise.

diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md
index eb99d3ab881e29f3069991e4f778be95d51ec4da..a823c4ddca420e0cca1caac59cbab59f17ec639c 100644
--- a/gcc/config/aarch64/aarch64-simd.md
+++ b/gcc/config/aarch64/aarch64-simd.md
@@ -705,12 +705,28 @@ (define_insn "aarch64_abs"
   [(set_attr "type" "neon_abs")]
 )
 
+;; Helper expander for aarch64_abd_3 to save the callers
+;; the hassle of constructing the other arm of the MINUS.
+(define_expand "abd_3"
+  [(use (match_operand:VDQ_BHSI 0 "register_operand"))
+   (USMAX:VDQ_BHSI (match_operand:VDQ_BHSI 1 "register_operand")
+		   (match_operand:VDQ_BHSI 2 "register_operand"))]
+  "TARGET_SIMD"
+  {
+rtx other_arm
+  = simplify_gen_binary (, mode, operands[1], operands[2]);
+emit_insn (gen_aarch64_abd_3 (operands[0], operands[1],
+	   operands[2], other_arm));
+DONE;
+  }
+)
+
 ;; It's tempting to represent SABD as ABS (MINUS op1 op2).
 ;; This isn't accurate as ABS treats always its input as a signed value.
 ;; So (ABS:QI (minus:QI 64 -128)) == (ABS:QI (192 or -64 signed)) == 64.
 ;; Whereas SABD would return 192 (-64 signed) on the above example.
 ;; Use MINUS ([us]max (op1, op2), [us]min (op1, op2)) instead.
-(define_insn "*aarch64_abd_3"
+(define_insn "aarch64_abd_3"
   [(set (match_operand:VDQ_BHSI 0 "register_operand" "=w")
 	(minus:VDQ_BHSI
 	  (USMAX:VDQ_BHSI
@@ -764,6 +780,13 @@ (define_insn "aarch64_adalp_3"
 ;; UABAL	tmp.8h, op1.16b, op2.16b
 ;; UADALP	op3.4s, tmp.8h
 ;; MOV		op0, op3 // should be eliminated in later passes.
+;;
+;; For TARGET_DOTPROD we do:
+;; MOV	tmp1.16b, #1 // Can be CSE'd and hoisted out of loops.
+;; UABD	tmp2.16b, op1.16b, op2.16b
+;; UDOT	op3.4s, tmp2.16b, tmp1.16b
+;; MOV	op0, op3 // RA will tie the operands of UDOT appropriately.
+;;
 ;; The signed version just uses the signed variants of the above instructions.
 
 (define_expand "sadv16qi"
@@ -773,6 +796,18 @@ (define_expand "sadv16qi"
(use (match_operand:V4SI 3 "register_operand"))]
   "TARGET_SIMD"
   {
+if (TARGET_DOTPROD)
+  {
+	rtx ones = gen_reg_rtx (V16QImode);
+	emit_move_insn (ones,
+			aarch64_simd_gen_const_vector_dup (V16QImode,
+			HOST_WIDE_INT_1));
+	rtx abd = gen_reg_rtx (V16QImode);
+	emit_insn (gen_abdv16qi_3 (abd, operands[1], operands[2]));
+	emit_insn (gen_aarch64_dotv16qi (operands[0], operands[3],
+	   abd, ones));
+	DONE;
+  }
 rtx reduc = gen_reg_rtx (V8HImode);
 emit_insn (gen_aarch64_abdl2v16qi_3 (reduc, operands[1],
 	   operands[2]));
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index 16e4dbda73ab928054590c47a4398408162c0332..5afb692493c6e9fa31355693e7843e4f0b1b281c 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -1059,6 +1059,9 @@ (define_code_attr f16mac [(plus "a") (minus "s")])
 ;; Map smax to smin and umax to umin.
 (define_code_attr max_opp [(smax "smin") (umax "umin")])
 
+;; Same as above, but louder.
+(define_code_attr MAX_OPP [(smax "SMIN") (umax "UMIN")])
+
 ;; The number of subvectors in an SVE_STRUCT.
 (define_mode_attr vector_count [(VNx32QI "2") (VNx16HI "2")
 (VNx8SI  "2") (VNx4DI  "2")
diff --git a/gcc/testsuite/gcc.target/aarch64/ssadv16qi-dotprod.c b/gcc/testsuite/gcc.target/aarch64/ssadv16qi-dotprod.c
new file mode 100644
index 0