diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 121da52b33cb622e31bbb0caa561bfc8d50ddf4f..c118e4ddca982c1a733ba4d98d6d70682d87faef 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2019-08-05  Richard Biener  <rguenther@suse.de>
+
+	PR middle-end/91169
+	* fold-const.c (get_array_ctor_element_at_index): Create
+	offset_ints according to the sign of the index type and treat
+	that as signed if it is obviously so.
+
 2019-08-05  Jakub Jelinek  <jakub@redhat.com>
 
 	PR target/91341
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 0a2410125be1548d12441fd64ab5ded21b9f28a8..716d7397b49bb4a4be4441396ade09692f9221d2 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -11850,6 +11850,7 @@ get_array_ctor_element_at_index (tree ctor, offset_int access_index,
 				 unsigned *ctor_idx)
 {
   tree index_type = NULL_TREE;
+  signop index_sgn = UNSIGNED;
   offset_int low_bound = 0;
 
   if (TREE_CODE (TREE_TYPE (ctor)) == ARRAY_TYPE)
@@ -11860,22 +11861,37 @@ get_array_ctor_element_at_index (tree ctor, offset_int access_index,
 	  /* Static constructors for variably sized objects makes no sense.  */
 	  gcc_assert (TREE_CODE (TYPE_MIN_VALUE (domain_type)) == INTEGER_CST);
 	  index_type = TREE_TYPE (TYPE_MIN_VALUE (domain_type));
-	  low_bound = wi::to_offset (TYPE_MIN_VALUE (domain_type));
+	  /* ???  When it is obvious that the range is signed, treat it so.  */
+	  if (TYPE_UNSIGNED (index_type)
+	      && TYPE_MAX_VALUE (domain_type)
+	      && tree_int_cst_lt (TYPE_MAX_VALUE (domain_type),
+				  TYPE_MIN_VALUE (domain_type)))
+	    {
+	      index_sgn = SIGNED;
+	      low_bound
+		= offset_int::from (wi::to_wide (TYPE_MIN_VALUE (domain_type)),
+				    SIGNED);
+	    }
+	  else
+	    {
+	      index_sgn = TYPE_SIGN (index_type);
+	      low_bound = wi::to_offset (TYPE_MIN_VALUE (domain_type));
+	    }
 	}
     }
 
   if (index_type)
     access_index = wi::ext (access_index, TYPE_PRECISION (index_type),
-			    TYPE_SIGN (index_type));
+			    index_sgn);
 
-  offset_int index = low_bound - 1;
+  offset_int index = low_bound;
   if (index_type)
-    index = wi::ext (index, TYPE_PRECISION (index_type),
-		     TYPE_SIGN (index_type));
+    index = wi::ext (index, TYPE_PRECISION (index_type), index_sgn);
 
-  offset_int max_index;
+  offset_int max_index = index;
   unsigned cnt;
   tree cfield, cval;
+  bool first_p = true;
 
   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, cval)
     {
@@ -11885,27 +11901,34 @@ get_array_ctor_element_at_index (tree ctor, offset_int access_index,
       if (cfield)
 	{
 	  if (TREE_CODE (cfield) == INTEGER_CST)
-	    max_index = index = wi::to_offset (cfield);
+	    max_index = index
+	      = offset_int::from (wi::to_wide (cfield), index_sgn);
 	  else
 	    {
 	      gcc_assert (TREE_CODE (cfield) == RANGE_EXPR);
-	      index = wi::to_offset (TREE_OPERAND (cfield, 0));
-	      max_index = wi::to_offset (TREE_OPERAND (cfield, 1));
+	      index = offset_int::from (wi::to_wide (TREE_OPERAND (cfield, 0)),
+					index_sgn);
+	      max_index
+	        = offset_int::from (wi::to_wide (TREE_OPERAND (cfield, 1)),
+				    index_sgn);
+	      gcc_checking_assert (wi::le_p (index, max_index, index_sgn));
 	    }
 	}
-      else
+      else if (!first_p)
 	{
-	  index += 1;
+	  index = max_index + 1;
 	  if (index_type)
-	    index = wi::ext (index, TYPE_PRECISION (index_type),
-			     TYPE_SIGN (index_type));
+	    index = wi::ext (index, TYPE_PRECISION (index_type), index_sgn);
+	  gcc_checking_assert (wi::gt_p (index, max_index, index_sgn));
 	  max_index = index;
 	}
+      else
+	first_p = false;
 
       /* Do we have match?  */
-      if (wi::cmpu (access_index, index) >= 0)
+      if (wi::cmp (access_index, index, index_sgn) >= 0)
 	{
-	  if (wi::cmpu (access_index, max_index) <= 0)
+	  if (wi::cmp (access_index, max_index, index_sgn) <= 0)
 	    {
 	      if (ctor_idx)
 		*ctor_idx = cnt;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index e19f136370bf62a90843e0a6c795da9b68153d3c..5dc9d11140b99b145b41dd4c9c96db6fb7b56d25 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2019-08-05  Richard Biener  <rguenther@suse.de>
+
+	PR middle-end/91169
+	* gnat.dg/array37.adb: New testcase.
+
 2019-08-05  Jakub Jelinek  <jakub@redhat.com>
 
 	PR target/91341
diff --git a/gcc/testsuite/gnat.dg/array37.adb b/gcc/testsuite/gnat.dg/array37.adb
new file mode 100644
index 0000000000000000000000000000000000000000..f1ee385d1a55a48473aa68b2c119cd7ee85cb79f
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/array37.adb
@@ -0,0 +1,19 @@
+-- { dg-do run }
+-- { dg-options "-O" }
+
+procedure Array37 is
+
+  type Arr is array (Integer range -1 .. 1) of Integer;
+
+  A : Arr := (-100, 0, 100);
+
+  function Ident (I : Integer) return Integer IS
+  begin
+    return I;
+  end;
+
+begin
+  if Ident (A (1)) <= Ident (A (0)) then
+    raise Program_Error;
+  end if;
+end;