public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* powerpc64 large-toc vs. reload
@ 2011-06-19 18:15 Alan Modra
  2011-06-20  8:06 ` David Edelsohn
  0 siblings, 1 reply; 3+ messages in thread
From: Alan Modra @ 2011-06-19 18:15 UTC (permalink / raw)
  To: gcc-patches, David Edelsohn

I was alerted to a problem with large toc (-mcmodel=medium/large) code
a few days ago by warnings emitted during a binutils build.

dwarf.c: In function 'display_debug_lines_raw':
dwarf.c:2409:1: note: non-delegitimized UNSPEC UNSPEC_TOCREL (44) found in variable location
dwarf.c:2409:1: note: non-delegitimized UNSPEC UNSPEC_TOCREL (44) found in variable location

On investigating why this was happening, I found that these UNSPECs
were from the high part calculation of a toc-relative address that
didn't get a register.  reload allocated the pseudo to a stack slot..
The stack slot didn't match the tight pattern in delegitimize_address
which is why we have an UNSPEC left in the debug info.  The real
problem of course is that reload should never allocate a stack slot
for a simple address calculation that can be rematerialised anywhere
in the function with just one instruction.  So after quite a bit of
digging around in reload, I finally figured out that the problem has a
really easy solution.  Simply tell reload that those high part address
calculations are constants.  Which is true.

That's what the create_TOC_reference change, and the rs6000.md changes
below do.  (I also fix large-toc tls patterns.)  The rest of the patch
just adjusts for the changed RTL.

Bootstrap and regression tests powerpc64-linux in progress.  OK to
apply mainline and 4.6 assuming no regressions?

	* config/rs6000/rs6000.c (create_TOC_reference): Wrap high part
	of toc-relative address in CONST.
	(rs6000_delegitimize_address): Recognize changed address.
	(rs6000_legitimize_reload_address): Likewise.
	(rs6000_emit_move): Don't force these constants to memory.
	* config/rs6000/rs6000.md (tls_gd, tls_gd_high): Wrap high part of
	toc-relative address in CONST.
	(tls_ld, tls_ld_high, tls_got_dtprel, tls_got_dtprel_high): Likewise.
	(tls_got_tprel, tls_got_tprel_high, largetoc_high): Likewise.

Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 175175)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -5803,12 +5803,13 @@ rs6000_delegitimize_address (rtx orig_x)
 		   || TARGET_MINIMAL_TOC
 		   || TARGET_CMODEL != CMODEL_SMALL))
 	      || (TARGET_CMODEL != CMODEL_SMALL
-		  && GET_CODE (XEXP (x, 0)) == PLUS
-		  && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
-		  && REGNO (XEXP (XEXP (x, 0), 0)) == TOC_REGISTER
-		  && GET_CODE (XEXP (XEXP (x, 0), 1)) == HIGH
+		  && GET_CODE (XEXP (x, 0)) == CONST
+		  && GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS
+		  && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == REG
+		  && REGNO (XEXP (XEXP (XEXP (x, 0), 0), 0)) == TOC_REGISTER
+		  && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == HIGH
 		  && rtx_equal_p (XEXP (x, 1),
-				  XEXP (XEXP (XEXP (x, 0), 1), 0)))))
+				  XEXP (XEXP (XEXP (XEXP (x, 0), 0), 1), 0)))))
 	{
 	  y = XVECEXP (y, 0, 0);
 	  if (offset != NULL_RTX)
@@ -6147,11 +6148,12 @@ rs6000_legitimize_reload_address (rtx x,
       && GET_CODE (XEXP (x, 0)) == PLUS
       && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
       && REGNO (XEXP (XEXP (x, 0), 0)) == TOC_REGISTER
-      && GET_CODE (XEXP (XEXP (x, 0), 1)) == HIGH
+      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST
+      && GET_CODE (XEXP (XEXP (XEXP (x, 0), 1), 0)) == HIGH
       && GET_CODE (XEXP (x, 1)) == CONST
       && GET_CODE (XEXP (XEXP (x, 1), 0)) == UNSPEC
       && XINT (XEXP (XEXP (x, 1), 0), 1) == UNSPEC_TOCREL
-      && rtx_equal_p (XEXP (XEXP (XEXP (x, 0), 1), 0), XEXP (x, 1)))
+      && rtx_equal_p (XEXP (XEXP (XEXP (XEXP (x, 0), 1), 0), 0), XEXP (x, 1)))
     {
       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
 		   BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
@@ -7197,6 +7196,11 @@ rs6000_emit_move (rtx dest, rtx source, 
 	}
       else if (mode == Pmode
 	       && CONSTANT_P (operands[1])
+	       && GET_CODE (operands[1]) != HIGH
+	       && !(TARGET_CMODEL != CMODEL_SMALL
+		    && GET_CODE (operands[1]) == CONST
+		    && GET_CODE (XEXP (operands[1], 0)) == PLUS
+		    && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == HIGH)
 	       && ((GET_CODE (operands[1]) != CONST_INT
 		    && ! easy_fp_constant (operands[1], mode))
 		   || (GET_CODE (operands[1]) == CONST_INT
@@ -7204,7 +7208,6 @@ rs6000_emit_move (rtx dest, rtx source, 
 			   > (TARGET_CMODEL != CMODEL_SMALL ? 3 : 2)))
 		   || (GET_CODE (operands[0]) == REG
 		       && FP_REGNO_P (REGNO (operands[0]))))
-	       && GET_CODE (operands[1]) != HIGH
 	       && ! legitimate_constant_pool_address_p (operands[1], mode,
 							false)
 	       && ! toc_relative_expr_p (operands[1])
@@ -19063,7 +19078,9 @@ create_TOC_reference (rtx symbol, rtx la
   tocreg = gen_rtx_REG (Pmode, TOC_REGISTER);
   if (TARGET_CMODEL != CMODEL_SMALL)
     {
-      rtx hi = gen_rtx_PLUS (Pmode, tocreg, gen_rtx_HIGH (Pmode, tocrel));
+      rtx hi = gen_rtx_CONST (Pmode,
+			      gen_rtx_PLUS (Pmode, tocreg, 
+					    gen_rtx_HIGH (Pmode, tocrel)));
       if (largetoc_reg != NULL)
 	{
 	  emit_move_insn (largetoc_reg, hi);
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md	(revision 175175)
+++ gcc/config/rs6000/rs6000.md	(working copy)
@@ -11523,9 +11523,10 @@ (define_insn_and_split "*tls_gd<TLSmode:
   "addi %0,%1,%2@got@tlsgd"
   "&& TARGET_CMODEL != CMODEL_SMALL"
   [(set (match_dup 3)
-  	(plus:TLSmode (match_dup 1)
-	  (high:TLSmode
-	    (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGD))))
+	(const:TLSmode
+	  (plus:TLSmode (match_dup 1)
+	    (high:TLSmode
+	      (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGD)))))
    (set (match_dup 0)
    	(lo_sum:TLSmode (match_dup 3)
 	    (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGD)))]
@@ -11540,10 +11541,11 @@ (define_insn_and_split "*tls_gd<TLSmode:
 
 (define_insn "*tls_gd_high<TLSmode:tls_abi_suffix>"
   [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-     (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
-       (high:TLSmode
-	  (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			  UNSPEC_TLSGD))))]
+     (const:TLSmode
+       (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
+	 (high:TLSmode
+	   (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
+			   UNSPEC_TLSGD)))))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
   "addis %0,%1,%2@got@tlsgd@ha"
   [(set_attr "length" "4")])
@@ -11658,9 +11660,10 @@ (define_insn_and_split "*tls_ld<TLSmode:
   "addi %0,%1,%&@got@tlsld"
   "&& TARGET_CMODEL != CMODEL_SMALL"
   [(set (match_dup 2)
-  	(plus:TLSmode (match_dup 1)
-	  (high:TLSmode
-	    (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD))))
+	(const:TLSmode
+	  (plus:TLSmode (match_dup 1)
+	    (high:TLSmode
+	      (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)))))
    (set (match_dup 0)
    	(lo_sum:TLSmode (match_dup 2)
 	    (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)))]
@@ -11675,9 +11678,10 @@ (define_insn_and_split "*tls_ld<TLSmode:
 
 (define_insn "*tls_ld_high<TLSmode:tls_abi_suffix>"
   [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-     (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
-       (high:TLSmode
-	  (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD))))]
+     (const:TLSmode
+       (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
+	 (high:TLSmode
+	   (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)))))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
   "addis %0,%1,%&@got@tlsld@ha"
   [(set_attr "length" "4")])
@@ -11753,9 +11757,10 @@ (define_insn_and_split "tls_got_dtprel_<
   "l<TLSmode:tls_insn_suffix> %0,%2@got@dtprel(%1)"
   "&& TARGET_CMODEL != CMODEL_SMALL"
   [(set (match_dup 3)
-	(plus:TLSmode (match_dup 1)
-	  (high:TLSmode
-	    (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTDTPREL))))
+	(const:TLSmode
+	  (plus:TLSmode (match_dup 1)
+	    (high:TLSmode
+	      (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTDTPREL)))))
    (set (match_dup 0)
 	(lo_sum:TLSmode (match_dup 3)
 	    (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTDTPREL)))]
@@ -11770,10 +11775,11 @@ (define_insn_and_split "tls_got_dtprel_<
 
 (define_insn "*tls_got_dtprel_high<TLSmode:tls_abi_suffix>"
   [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-     (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
-       (high:TLSmode
-	 (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			 UNSPEC_TLSGOTDTPREL))))]
+     (const:TLSmode
+       (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
+	 (high:TLSmode
+	   (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
+			   UNSPEC_TLSGOTDTPREL)))))]
   "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL"
   "addis %0,%1,%2@got@dtprel@ha"
   [(set_attr "length" "4")])
@@ -11823,9 +11829,10 @@ (define_insn_and_split "tls_got_tprel_<T
   "l<TLSmode:tls_insn_suffix> %0,%2@got@tprel(%1)"
   "&& TARGET_CMODEL != CMODEL_SMALL"
   [(set (match_dup 3)
-	(plus:TLSmode (match_dup 1)
-	  (high:TLSmode
-	    (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTTPREL))))
+	(const:TLSmode
+	  (plus:TLSmode (match_dup 1)
+	    (high:TLSmode
+	      (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTTPREL)))))
    (set (match_dup 0)
 	(lo_sum:TLSmode (match_dup 3)
 	    (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTTPREL)))]
@@ -11840,10 +11847,11 @@ (define_insn_and_split "tls_got_tprel_<T
 
 (define_insn "*tls_got_tprel_high<TLSmode:tls_abi_suffix>"
   [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-     (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
-       (high:TLSmode
-	 (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			 UNSPEC_TLSGOTTPREL))))]
+     (const:TLSmode
+       (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
+	 (high:TLSmode
+	   (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
+			   UNSPEC_TLSGOTTPREL)))))]
   "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL"
   "addis %0,%1,%2@got@tprel@ha"
   [(set_attr "length" "4")])
@@ -12157,8 +12165,9 @@ (define_insn "elf_low"
 ;; Largetoc support
 (define_insn "largetoc_high"
   [(set (match_operand:DI 0 "gpc_reg_operand" "=b")
-        (plus:DI (match_operand:DI 1 "gpc_reg_operand" "b")
-	         (high:DI (match_operand:DI 2 "" ""))))]
+	(const:DI
+	  (plus:DI (match_operand:DI 1 "gpc_reg_operand" "b")
+		   (high:DI (match_operand:DI 2 "" "")))))]
    "TARGET_ELF && TARGET_CMODEL != CMODEL_SMALL"
    "{cau|addis} %0,%1,%2@ha")
 

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: powerpc64 large-toc vs. reload
  2011-06-19 18:15 powerpc64 large-toc vs. reload Alan Modra
@ 2011-06-20  8:06 ` David Edelsohn
  2011-06-20 15:18   ` Alan Modra
  0 siblings, 1 reply; 3+ messages in thread
From: David Edelsohn @ 2011-06-20  8:06 UTC (permalink / raw)
  To: gcc-patches, Alan Modra

On Sun, Jun 19, 2011 at 10:03 AM, Alan Modra <amodra@gmail.com> wrote:
> I was alerted to a problem with large toc (-mcmodel=medium/large) code
> a few days ago by warnings emitted during a binutils build.
>
> dwarf.c: In function 'display_debug_lines_raw':
> dwarf.c:2409:1: note: non-delegitimized UNSPEC UNSPEC_TOCREL (44) found in variable location
> dwarf.c:2409:1: note: non-delegitimized UNSPEC UNSPEC_TOCREL (44) found in variable location
>
> On investigating why this was happening, I found that these UNSPECs
> were from the high part calculation of a toc-relative address that
> didn't get a register.  reload allocated the pseudo to a stack slot..
> The stack slot didn't match the tight pattern in delegitimize_address
> which is why we have an UNSPEC left in the debug info.  The real
> problem of course is that reload should never allocate a stack slot
> for a simple address calculation that can be rematerialised anywhere
> in the function with just one instruction.  So after quite a bit of
> digging around in reload, I finally figured out that the problem has a
> really easy solution.  Simply tell reload that those high part address
> calculations are constants.  Which is true.
>
> That's what the create_TOC_reference change, and the rs6000.md changes
> below do.  (I also fix large-toc tls patterns.)  The rest of the patch
> just adjusts for the changed RTL.
>
> Bootstrap and regression tests powerpc64-linux in progress.  OK to
> apply mainline and 4.6 assuming no regressions?
>
>        * config/rs6000/rs6000.c (create_TOC_reference): Wrap high part
>        of toc-relative address in CONST.
>        (rs6000_delegitimize_address): Recognize changed address.
>        (rs6000_legitimize_reload_address): Likewise.
>        (rs6000_emit_move): Don't force these constants to memory.
>        * config/rs6000/rs6000.md (tls_gd, tls_gd_high): Wrap high part of
>        toc-relative address in CONST.
>        (tls_ld, tls_ld_high, tls_got_dtprel, tls_got_dtprel_high): Likewise.
>        (tls_got_tprel, tls_got_tprel_high, largetoc_high): Likewise.

Okay.

Thanks, David

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: powerpc64 large-toc vs. reload
  2011-06-20  8:06 ` David Edelsohn
@ 2011-06-20 15:18   ` Alan Modra
  0 siblings, 0 replies; 3+ messages in thread
From: Alan Modra @ 2011-06-20 15:18 UTC (permalink / raw)
  To: David Edelsohn, gcc-patches

On Sun, Jun 19, 2011 at 11:04:12PM -0400, David Edelsohn wrote:
> On Sun, Jun 19, 2011 at 10:03 AM, Alan Modra <amodra@gmail.com> wrote:
> >        * config/rs6000/rs6000.c (create_TOC_reference): Wrap high part
> >        of toc-relative address in CONST.
> >        (rs6000_delegitimize_address): Recognize changed address.
> >        (rs6000_legitimize_reload_address): Likewise.
> >        (rs6000_emit_move): Don't force these constants to memory.
> >        * config/rs6000/rs6000.md (tls_gd, tls_gd_high): Wrap high part of
> >        toc-relative address in CONST.
> >        (tls_ld, tls_ld_high, tls_got_dtprel, tls_got_dtprel_high): Likewise.
> >        (tls_got_tprel, tls_got_tprel_high, largetoc_high): Likewise.
> 
> Okay.

I applied this after boostrapping c,c++,fortran,lto and finding no
regressions, both on mainline and gcc-4.6.  Then I did the same for
gcc-4.6-ibm and gcc-4.5-ibm, and discovered an internal compiler error
on the gcc-4.5-ibm branch in one fortran testcase.  Arrgh!  This was
due to reload putting one of the new CONST patterns in the constant
pool.  I'm almost certain this can happen on mainline and 4.6 too but
just doesn't trigger on the testsuite or during bootstrap.

So I need to make a followup patch and match the new CONST pattern in
rs6000_cannot_force_const_mem.  reload.c:CONST_POOL_OK_P will then
prevent reload putting these constants into memory.

Bootstrapped and regression tested all over again.  This is what I'm
about to commit.

	* config/rs6000/rs6000.c (rs6000_cannot_force_const_mem): Match
	CONST high part large-toc address.
	(rs6000_tls_referenced_p): Make static.
	* config/rs6000/rs6000-protos.h (rs6000_tls_referenced_p): Delete.

Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 175200)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -6045,7 +6045,7 @@ rs6000_legitimize_tls_address (rtx addr,
 
 /* Return 1 if X contains a thread-local symbol.  */
 
-bool
+static bool
 rs6000_tls_referenced_p (rtx x)
 {
   if (! TARGET_HAVE_TLS)
@@ -6059,6 +6059,11 @@ rs6000_tls_referenced_p (rtx x)
 static bool
 rs6000_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
 {
+  if (GET_CODE (x) == CONST
+      && GET_CODE (XEXP (x, 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (x, 0), 1)) == HIGH)
+    return true;
+
   return rs6000_tls_referenced_p (x);
 }
 
Index: gcc/config/rs6000/rs6000-protos.h
===================================================================
--- gcc/config/rs6000/rs6000-protos.h	(revision 175200)
+++ gcc/config/rs6000/rs6000-protos.h	(working copy)
@@ -171,7 +171,6 @@ extern unsigned int rs6000_dbx_register_
 extern void rs6000_emit_epilogue (int);
 extern void rs6000_emit_eh_reg_restore (rtx, rtx);
 extern const char * output_isel (rtx *);
-extern bool rs6000_tls_referenced_p (rtx);
 
 extern void rs6000_aix_asm_output_dwarf_table_ref (char *);
 

The 4.6 patch is a little different due to 4.5 not already having
rs6000_cannot_force_const_mem.

	* config/rs6000/rs6000.c (rs6000_cannot_force_const_mem): New func.
	(TARGET_CANNOT_FORCE_CONST_MEM): Update definition.

Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 175201)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -1212,6 +1212,7 @@ static enum machine_mode rs6000_eh_retur
 static bool rs6000_can_eliminate (const int, const int);
 static void rs6000_conditional_register_usage (void);
 static void rs6000_trampoline_init (rtx, tree, rtx);
+static bool rs6000_cannot_force_const_mem (rtx);
 
 /* Hash table stuff for keeping track of TOC entries.  */
 
@@ -1382,7 +1383,7 @@ static const struct default_options rs60
 #define TARGET_HAVE_TLS HAVE_AS_TLS
 
 #undef TARGET_CANNOT_FORCE_CONST_MEM
-#define TARGET_CANNOT_FORCE_CONST_MEM rs6000_tls_referenced_p
+#define TARGET_CANNOT_FORCE_CONST_MEM rs6000_cannot_force_const_mem
 
 #undef TARGET_DELEGITIMIZE_ADDRESS
 #define TARGET_DELEGITIMIZE_ADDRESS rs6000_delegitimize_address
@@ -6651,6 +6663,19 @@ rs6000_tls_referenced_p (rtx x)
   return for_each_rtx (&x, &rs6000_tls_symbol_ref_1, 0);
 }
 
+/* Implement TARGET_CANNOT_FORCE_CONST_MEM.  */
+
+static bool
+rs6000_cannot_force_const_mem (rtx x)
+{
+  if (GET_CODE (x) == CONST
+      && GET_CODE (XEXP (x, 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (x, 0), 1)) == HIGH)
+    return true;
+
+  return rs6000_tls_referenced_p (x);
+}
+
 /* Return 1 if *X is a thread-local symbol.  This is the same as
    rs6000_tls_symbol_ref except for the type of the unused argument.  */
 

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2011-06-20 15:04 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-06-19 18:15 powerpc64 large-toc vs. reload Alan Modra
2011-06-20  8:06 ` David Edelsohn
2011-06-20 15:18   ` Alan Modra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).