[46/55] rs6000: Builtin expansion, part 3

Message ID 7d3846877141b74d4042aec96b9147a7e9d7285c.1623941442.git.wschmidt@linux.ibm.com
State Superseded
Headers show
Series
  • Replace the Power target-specific builtin machinery
Related show

Commit Message

Richard Biener via Gcc-patches June 17, 2021, 3:19 p.m.
2021-03-05  Bill Schmidt  <wschmidt@linux.ibm.com>

gcc/
	* config/rs6000/rs6000-call.c (new_cpu_expand_builtin):
	Implement.
---
 gcc/config/rs6000/rs6000-call.c | 100 ++++++++++++++++++++++++++++++++
 1 file changed, 100 insertions(+)

-- 
2.27.0

Comments

Richard Biener via Gcc-patches July 27, 2021, 9:06 p.m. | #1
On Thu, 2021-06-17 at 10:19 -0500, Bill Schmidt via Gcc-patches wrote:
> 2021-03-05  Bill Schmidt  <wschmidt@linux.ibm.com>

> 


Hi,


> gcc/

> 	* config/rs6000/rs6000-call.c (new_cpu_expand_builtin):

> 	Implement.


ok


> ---

>  gcc/config/rs6000/rs6000-call.c | 100 ++++++++++++++++++++++++++++++++

>  1 file changed, 100 insertions(+)

> 

> diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c

> index 754cd46b1c1..ad3e6a4bbe5 100644

> --- a/gcc/config/rs6000/rs6000-call.c

> +++ b/gcc/config/rs6000/rs6000-call.c

> @@ -14604,6 +14604,106 @@ static rtx

>  new_cpu_expand_builtin (enum rs6000_gen_builtins fcode,

>  			tree exp ATTRIBUTE_UNUSED, rtx target)

>  {

> +  /* __builtin_cpu_init () is a nop, so expand to nothing.  */

> +  if (fcode == RS6000_BIF_CPU_INIT)

> +    return const0_rtx;

> +

> +  if (target == 0 || GET_MODE (target) != SImode)

> +    target = gen_reg_rtx (SImode);

> +

> +#ifdef TARGET_LIBC_PROVIDES_HWCAP_IN_TCB

> +  tree arg = TREE_OPERAND (CALL_EXPR_ARG (exp, 0), 0);

> +  /* Target clones creates an ARRAY_REF instead of STRING_CST, convert it back

> +     to a STRING_CST.  */

> +  if (TREE_CODE (arg) == ARRAY_REF

> +      && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST

> +      && TREE_CODE (TREE_OPERAND (arg, 1)) == INTEGER_CST

> +      && compare_tree_int (TREE_OPERAND (arg, 1), 0) == 0)

> +    arg = TREE_OPERAND (arg, 0);

> +

> +  if (TREE_CODE (arg) != STRING_CST)

> +    {

> +      error ("builtin %qs only accepts a string argument",

> +	     rs6000_builtin_info_x[(size_t) fcode].bifname);

> +      return const0_rtx;

> +    }

> +

> +  if (fcode == RS6000_BIF_CPU_IS)

> +    {

> +      const char *cpu = TREE_STRING_POINTER (arg);

> +      rtx cpuid = NULL_RTX;

> +      for (size_t i = 0; i < ARRAY_SIZE (cpu_is_info); i++)

> +	if (strcmp (cpu, cpu_is_info[i].cpu) == 0)

> +	  {

> +	    /* The CPUID value in the TCB is offset by _DL_FIRST_PLATFORM.  */

> +	    cpuid = GEN_INT (cpu_is_info[i].cpuid + _DL_FIRST_PLATFORM);

> +	    break;

> +	  }


ok

> +      if (cpuid == NULL_RTX)

> +	{

> +	  /* Invalid CPU argument.  */

> +	  error ("cpu %qs is an invalid argument to builtin %qs",

> +		 cpu, rs6000_builtin_info_x[(size_t) fcode].bifname);

> +	  return const0_rtx;

> +	}

> +

> +      rtx platform = gen_reg_rtx (SImode);

> +      rtx tcbmem = gen_const_mem (SImode,

> +				  gen_rtx_PLUS (Pmode,

> +						gen_rtx_REG (Pmode, TLS_REGNUM),

> +						GEN_INT (TCB_PLATFORM_OFFSET)));

> +      emit_move_insn (platform, tcbmem);

> +      emit_insn (gen_eqsi3 (target, platform, cpuid));

> +    }

> +  else if (fcode == RS6000_BIF_CPU_SUPPORTS)

> +    {

> +      const char *hwcap = TREE_STRING_POINTER (arg);

> +      rtx mask = NULL_RTX;

> +      int hwcap_offset;

> +      for (size_t i = 0; i < ARRAY_SIZE (cpu_supports_info); i++)

> +	if (strcmp (hwcap, cpu_supports_info[i].hwcap) == 0)

> +	  {

> +	    mask = GEN_INT (cpu_supports_info[i].mask);

> +	    hwcap_offset = TCB_HWCAP_OFFSET (cpu_supports_info[i].id);

> +	    break;

> +	  }

> +      if (mask == NULL_RTX)

> +	{

> +	  /* Invalid HWCAP argument.  */

> +	  error ("%s %qs is an invalid argument to builtin %qs",

> +		 "hwcap", hwcap,

> +		 rs6000_builtin_info_x[(size_t) fcode].bifname);

> +	  return const0_rtx;

> +	}

> +

> +      rtx tcb_hwcap = gen_reg_rtx (SImode);

> +      rtx tcbmem = gen_const_mem (SImode,

> +				  gen_rtx_PLUS (Pmode,

> +						gen_rtx_REG (Pmode, TLS_REGNUM),

> +						GEN_INT (hwcap_offset)));

> +      emit_move_insn (tcb_hwcap, tcbmem);

> +      rtx scratch1 = gen_reg_rtx (SImode);

> +      emit_insn (gen_rtx_SET (scratch1, gen_rtx_AND (SImode, tcb_hwcap, mask)));

> +      rtx scratch2 = gen_reg_rtx (SImode);

> +      emit_insn (gen_eqsi3 (scratch2, scratch1, const0_rtx));

> +      emit_insn (gen_rtx_SET (target, gen_rtx_XOR (SImode, scratch2, const1_rtx)));

> +    }

> +  else

> +    gcc_unreachable ();

> +

> +  /* Record that we have expanded a CPU builtin, so that we can later

> +     emit a reference to the special symbol exported by LIBC to ensure we

> +     do not link against an old LIBC that doesn't support this feature.  */

> +  cpu_builtin_p = true;

> +

> +#else

> +  warning (0, "builtin %qs needs GLIBC (2.23 and newer) that exports hardware "

> +	   "capability bits", rs6000_builtin_info_x[(size_t) fcode].bifname);

> +


This seems OK. 
It appears to comply with the documentation at least  :-)
	"If GCC was configured to use a GLIBC before 2.23, the built-in
	function __builtin_cpu_is always returns a 0 and the compiler
	issues a warning."

ok
lgtm,
thanks
-Will

> +  /* For old LIBCs, always return FALSE.  */

> +  emit_move_insn (target, GEN_INT (0));

> +#endif /* TARGET_LIBC_PROVIDES_HWCAP_IN_TCB */

> +

>    return target;

>  }

>
Segher Boessenkool Aug. 3, 2021, 11:40 p.m. | #2
On Tue, Jul 27, 2021 at 04:06:39PM -0500, will schmidt wrote:
> On Thu, 2021-06-17 at 10:19 -0500, Bill Schmidt via Gcc-patches wrote:

> > +#else

> > +  warning (0, "builtin %qs needs GLIBC (2.23 and newer) that exports hardware "

> > +	   "capability bits", rs6000_builtin_info_x[(size_t) fcode].bifname);

> > +

> 

> This seems OK. 

> It appears to comply with the documentation at least  :-)

> 	"If GCC was configured to use a GLIBC before 2.23, the built-in

> 	function __builtin_cpu_is always returns a 0 and the compiler

> 	issues a warning."


Yup.  And we still (have to) support older glibc versions, since various
distros ship with something older (2.23 is only 5 years old).


Segher

Patch

diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index 754cd46b1c1..ad3e6a4bbe5 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -14604,6 +14604,106 @@  static rtx
 new_cpu_expand_builtin (enum rs6000_gen_builtins fcode,
 			tree exp ATTRIBUTE_UNUSED, rtx target)
 {
+  /* __builtin_cpu_init () is a nop, so expand to nothing.  */
+  if (fcode == RS6000_BIF_CPU_INIT)
+    return const0_rtx;
+
+  if (target == 0 || GET_MODE (target) != SImode)
+    target = gen_reg_rtx (SImode);
+
+#ifdef TARGET_LIBC_PROVIDES_HWCAP_IN_TCB
+  tree arg = TREE_OPERAND (CALL_EXPR_ARG (exp, 0), 0);
+  /* Target clones creates an ARRAY_REF instead of STRING_CST, convert it back
+     to a STRING_CST.  */
+  if (TREE_CODE (arg) == ARRAY_REF
+      && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST
+      && TREE_CODE (TREE_OPERAND (arg, 1)) == INTEGER_CST
+      && compare_tree_int (TREE_OPERAND (arg, 1), 0) == 0)
+    arg = TREE_OPERAND (arg, 0);
+
+  if (TREE_CODE (arg) != STRING_CST)
+    {
+      error ("builtin %qs only accepts a string argument",
+	     rs6000_builtin_info_x[(size_t) fcode].bifname);
+      return const0_rtx;
+    }
+
+  if (fcode == RS6000_BIF_CPU_IS)
+    {
+      const char *cpu = TREE_STRING_POINTER (arg);
+      rtx cpuid = NULL_RTX;
+      for (size_t i = 0; i < ARRAY_SIZE (cpu_is_info); i++)
+	if (strcmp (cpu, cpu_is_info[i].cpu) == 0)
+	  {
+	    /* The CPUID value in the TCB is offset by _DL_FIRST_PLATFORM.  */
+	    cpuid = GEN_INT (cpu_is_info[i].cpuid + _DL_FIRST_PLATFORM);
+	    break;
+	  }
+      if (cpuid == NULL_RTX)
+	{
+	  /* Invalid CPU argument.  */
+	  error ("cpu %qs is an invalid argument to builtin %qs",
+		 cpu, rs6000_builtin_info_x[(size_t) fcode].bifname);
+	  return const0_rtx;
+	}
+
+      rtx platform = gen_reg_rtx (SImode);
+      rtx tcbmem = gen_const_mem (SImode,
+				  gen_rtx_PLUS (Pmode,
+						gen_rtx_REG (Pmode, TLS_REGNUM),
+						GEN_INT (TCB_PLATFORM_OFFSET)));
+      emit_move_insn (platform, tcbmem);
+      emit_insn (gen_eqsi3 (target, platform, cpuid));
+    }
+  else if (fcode == RS6000_BIF_CPU_SUPPORTS)
+    {
+      const char *hwcap = TREE_STRING_POINTER (arg);
+      rtx mask = NULL_RTX;
+      int hwcap_offset;
+      for (size_t i = 0; i < ARRAY_SIZE (cpu_supports_info); i++)
+	if (strcmp (hwcap, cpu_supports_info[i].hwcap) == 0)
+	  {
+	    mask = GEN_INT (cpu_supports_info[i].mask);
+	    hwcap_offset = TCB_HWCAP_OFFSET (cpu_supports_info[i].id);
+	    break;
+	  }
+      if (mask == NULL_RTX)
+	{
+	  /* Invalid HWCAP argument.  */
+	  error ("%s %qs is an invalid argument to builtin %qs",
+		 "hwcap", hwcap,
+		 rs6000_builtin_info_x[(size_t) fcode].bifname);
+	  return const0_rtx;
+	}
+
+      rtx tcb_hwcap = gen_reg_rtx (SImode);
+      rtx tcbmem = gen_const_mem (SImode,
+				  gen_rtx_PLUS (Pmode,
+						gen_rtx_REG (Pmode, TLS_REGNUM),
+						GEN_INT (hwcap_offset)));
+      emit_move_insn (tcb_hwcap, tcbmem);
+      rtx scratch1 = gen_reg_rtx (SImode);
+      emit_insn (gen_rtx_SET (scratch1, gen_rtx_AND (SImode, tcb_hwcap, mask)));
+      rtx scratch2 = gen_reg_rtx (SImode);
+      emit_insn (gen_eqsi3 (scratch2, scratch1, const0_rtx));
+      emit_insn (gen_rtx_SET (target, gen_rtx_XOR (SImode, scratch2, const1_rtx)));
+    }
+  else
+    gcc_unreachable ();
+
+  /* Record that we have expanded a CPU builtin, so that we can later
+     emit a reference to the special symbol exported by LIBC to ensure we
+     do not link against an old LIBC that doesn't support this feature.  */
+  cpu_builtin_p = true;
+
+#else
+  warning (0, "builtin %qs needs GLIBC (2.23 and newer) that exports hardware "
+	   "capability bits", rs6000_builtin_info_x[(size_t) fcode].bifname);
+
+  /* For old LIBCs, always return FALSE.  */
+  emit_move_insn (target, GEN_INT (0));
+#endif /* TARGET_LIBC_PROVIDES_HWCAP_IN_TCB */
+
   return target;
 }