[v2,4/6] arm, aarch64: Add support for __GCC_ASM_FLAG_OUTPUTS__
diff mbox series

Message ID 20191114100716.28827-5-richard.henderson@linaro.org
State New
Headers show
Series
  • Implement asm flag outputs for arm + aarch64
Related show

Commit Message

Richard Henderson Nov. 14, 2019, 10:07 a.m. UTC
Since all but a couple of lines is shared between the two targets,
enable them both at once.

	* config/arm/aarch-common-protos.h (arm_md_asm_adjust): Declare.
	* config/arm/aarch-common.c (arm_md_asm_adjust): New.
	* config/arm/arm-c.c (arm_cpu_builtins): Define
	__GCC_ASM_FLAG_OUTPUTS__.
	* config/arm/arm.c (TARGET_MD_ASM_ADJUST): New.
	* config/aarch64/aarch64-c.c (aarch64_define_unconditional_macros):
	Define __GCC_ASM_FLAG_OUTPUTS__.
	* config/aarch64/aarch64.c (TARGET_MD_ASM_ADJUST): New.
	* doc/extend.texi (FlagOutputOperands): Add documentation
	for ARM and AArch64.
---
 gcc/config/arm/aarch-common-protos.h |   6 ++
 gcc/config/aarch64/aarch64-c.c       |   2 +
 gcc/config/aarch64/aarch64.c         |   3 +
 gcc/config/arm/aarch-common.c        | 136 +++++++++++++++++++++++++++
 gcc/config/arm/arm-c.c               |   1 +
 gcc/config/arm/arm.c                 |   3 +
 gcc/doc/extend.texi                  |  39 ++++++++
 7 files changed, 190 insertions(+)

Comments

Richard Earnshaw (lists) Nov. 14, 2019, 2:39 p.m. UTC | #1
Not had a chance to look at this in detail, but I don't see any support for

1) Thumb1 where we do not expose the condition codes at all
2) Thumb2 where we need IT instructions along-side the conditional 
instructions themselves.

How have you tested this for those targets?

R.

On 14/11/2019 10:07, Richard Henderson wrote:
> Since all but a couple of lines is shared between the two targets,
> enable them both at once.
> 
> 	* config/arm/aarch-common-protos.h (arm_md_asm_adjust): Declare.
> 	* config/arm/aarch-common.c (arm_md_asm_adjust): New.
> 	* config/arm/arm-c.c (arm_cpu_builtins): Define
> 	__GCC_ASM_FLAG_OUTPUTS__.
> 	* config/arm/arm.c (TARGET_MD_ASM_ADJUST): New.
> 	* config/aarch64/aarch64-c.c (aarch64_define_unconditional_macros):
> 	Define __GCC_ASM_FLAG_OUTPUTS__.
> 	* config/aarch64/aarch64.c (TARGET_MD_ASM_ADJUST): New.
> 	* doc/extend.texi (FlagOutputOperands): Add documentation
> 	for ARM and AArch64.
> ---
>   gcc/config/arm/aarch-common-protos.h |   6 ++
>   gcc/config/aarch64/aarch64-c.c       |   2 +
>   gcc/config/aarch64/aarch64.c         |   3 +
>   gcc/config/arm/aarch-common.c        | 136 +++++++++++++++++++++++++++
>   gcc/config/arm/arm-c.c               |   1 +
>   gcc/config/arm/arm.c                 |   3 +
>   gcc/doc/extend.texi                  |  39 ++++++++
>   7 files changed, 190 insertions(+)
> 
> diff --git a/gcc/config/arm/aarch-common-protos.h b/gcc/config/arm/aarch-common-protos.h
> index 3bf38a104f6..f15cf336e9d 100644
> --- a/gcc/config/arm/aarch-common-protos.h
> +++ b/gcc/config/arm/aarch-common-protos.h
> @@ -23,6 +23,8 @@
>   #ifndef GCC_AARCH_COMMON_PROTOS_H
>   #define GCC_AARCH_COMMON_PROTOS_H
>   
> +#include "hard-reg-set.h"
> +
>   extern int aarch_accumulator_forwarding (rtx_insn *, rtx_insn *);
>   extern bool aarch_rev16_p (rtx);
>   extern bool aarch_rev16_shleft_mask_imm_p (rtx, machine_mode);
> @@ -141,5 +143,9 @@ struct cpu_cost_table
>     const struct vector_cost_table vect;
>   };
>   
> +rtx_insn *
> +arm_md_asm_adjust (vec<rtx> &outputs, vec<rtx> &/*inputs*/,
> +		    vec<const char *> &constraints,
> +		    vec<rtx> &clobbers, HARD_REG_SET &clobbered_regs);
>   
>   #endif /* GCC_AARCH_COMMON_PROTOS_H */
> diff --git a/gcc/config/aarch64/aarch64-c.c b/gcc/config/aarch64/aarch64-c.c
> index 7c322ca0813..0af859f1c14 100644
> --- a/gcc/config/aarch64/aarch64-c.c
> +++ b/gcc/config/aarch64/aarch64-c.c
> @@ -69,6 +69,8 @@ aarch64_define_unconditional_macros (cpp_reader *pfile)
>     builtin_define ("__ARM_FEATURE_UNALIGNED");
>     builtin_define ("__ARM_PCS_AAPCS64");
>     builtin_define_with_int_value ("__ARM_SIZEOF_WCHAR_T", WCHAR_TYPE_SIZE / 8);
> +
> +  builtin_define ("__GCC_ASM_FLAG_OUTPUTS__");
>   }
>   
>   /* Undefine/redefine macros that depend on the current backend state and may
> diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
> index d2a3c7ef90a..9a5f27fea3a 100644
> --- a/gcc/config/aarch64/aarch64.c
> +++ b/gcc/config/aarch64/aarch64.c
> @@ -21933,6 +21933,9 @@ aarch64_libgcc_floating_mode_supported_p
>   #undef TARGET_STRICT_ARGUMENT_NAMING
>   #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
>   
> +#undef TARGET_MD_ASM_ADJUST
> +#define TARGET_MD_ASM_ADJUST arm_md_asm_adjust
> +
>   struct gcc_target targetm = TARGET_INITIALIZER;
>   
>   #include "gt-aarch64.h"
> diff --git a/gcc/config/arm/aarch-common.c b/gcc/config/arm/aarch-common.c
> index 965a07a43e3..760ef6c9c0a 100644
> --- a/gcc/config/arm/aarch-common.c
> +++ b/gcc/config/arm/aarch-common.c
> @@ -26,10 +26,16 @@
>   #include "config.h"
>   #include "system.h"
>   #include "coretypes.h"
> +#include "insn-modes.h"
>   #include "tm.h"
>   #include "rtl.h"
>   #include "rtl-iter.h"
>   #include "memmodel.h"
> +#include "diagnostic.h"
> +#include "tree.h"
> +#include "expr.h"
> +#include "function.h"
> +#include "emit-rtl.h"
>   
>   /* Return TRUE if X is either an arithmetic shift left, or
>      is a multiplication by a power of two.  */
> @@ -520,3 +526,133 @@ arm_mac_accumulator_is_mul_result (rtx producer, rtx consumer)
>             && !reg_overlap_mentioned_p (mul_result, mac_op0)
>             && !reg_overlap_mentioned_p (mul_result, mac_op1));
>   }
> +
> +/* Worker function for TARGET_MD_ASM_ADJUST.
> +   We implement asm flag outputs.  */
> +
> +rtx_insn *
> +arm_md_asm_adjust (vec<rtx> &outputs, vec<rtx> &/*inputs*/,
> +		    vec<const char *> &constraints,
> +		    vec<rtx> &/*clobbers*/, HARD_REG_SET &/*clobbered_regs*/)
> +{
> +  bool saw_asm_flag = false;
> +
> +  start_sequence ();
> +  for (unsigned i = 0, n = outputs.length (); i < n; ++i)
> +    {
> +      const char *con = constraints[i];
> +      if (strncmp (con, "=@cc", 4) != 0)
> +	continue;
> +      con += 4;
> +      if (strchr (con, ',') != NULL)
> +	{
> +	  error ("alternatives not allowed in %<asm%> flag output");
> +	  continue;
> +	}
> +
> +      machine_mode mode;
> +      rtx_code code;
> +      int con01 = 0;
> +
> +#define C(X, Y)  (unsigned char)(X) * 256 + (unsigned char)(Y)
> +
> +      /* All of the condition codes are two characters.  */
> +      if (con[0] != 0 && con[1] != 0 && con[2] == 0)
> +	con01 = C(con[0], con[1]);
> +
> +      switch (con01)
> +	{
> +	case C('c', 'c'):
> +	case C('l', 'o'):
> +	  mode = CC_Cmode, code = GEU;
> +	  break;
> +	case C('c', 's'):
> +	case C('h', 's'):
> +	  mode = CC_Cmode, code = LTU;
> +	  break;
> +	case C('e', 'q'):
> +	  mode = CC_NZmode, code = EQ;
> +	  break;
> +	case C('g', 'e'):
> +	  mode = CCmode, code = GE;
> +	  break;
> +	case C('g', 't'):
> +	  mode = CCmode, code = GT;
> +	  break;
> +	case C('h', 'i'):
> +	  mode = CCmode, code = GTU;
> +	  break;
> +	case C('l', 'e'):
> +	  mode = CCmode, code = LE;
> +	  break;
> +	case C('l', 's'):
> +	  mode = CCmode, code = LEU;
> +	  break;
> +	case C('l', 't'):
> +	  mode = CCmode, code = LT;
> +	  break;
> +	case C('m', 'i'):
> +	  mode = CC_NZmode, code = LT;
> +	  break;
> +	case C('n', 'e'):
> +	  mode = CC_NZmode, code = NE;
> +	  break;
> +	case C('p', 'l'):
> +	  mode = CC_NZmode, code = GE;
> +	  break;
> +	case C('v', 'c'):
> +	  mode = CC_Vmode, code = EQ;
> +	  break;
> +	case C('v', 's'):
> +	  mode = CC_Vmode, code = NE;
> +	  break;
> +	default:
> +	  error ("unknown %<asm%> flag output %qs", constraints[i]);
> +	  continue;
> +	}
> +
> +#undef C
> +
> +      rtx dest = outputs[i];
> +      machine_mode dest_mode = GET_MODE (dest);
> +      if (!SCALAR_INT_MODE_P (dest_mode))
> +	{
> +	  error ("invalid type for %<asm%> flag output");
> +	  continue;
> +	}
> +
> +      if (!saw_asm_flag)
> +	{
> +	  /* This is the first asm flag output.  Here we put the flags
> +	     register in as the real output and adjust the condition to
> +	     allow it.  */
> +	  constraints[i] = "=c";
> +	  outputs[i] = gen_rtx_REG (CCmode, CC_REGNUM);
> +	  saw_asm_flag = true;
> +	}
> +      else
> +	{
> +	  /* We don't need the flags register as output twice.  */
> +	  constraints[i] = "=X";
> +	  outputs[i] = gen_rtx_SCRATCH (word_mode);
> +	}
> +
> +      rtx x = gen_rtx_REG (mode, CC_REGNUM);
> +      x = gen_rtx_fmt_ee (code, word_mode, x, const0_rtx);
> +
> +      if (dest_mode == word_mode)
> +	emit_insn (gen_rtx_SET (dest, x));
> +      else
> +	{
> +	  rtx tmp = gen_reg_rtx (word_mode);
> +	  emit_insn (gen_rtx_SET (tmp, x));
> +
> +	  tmp = convert_modes (dest_mode, word_mode, tmp, true);
> +	  emit_move_insn (dest, tmp);
> +	}
> +    }
> +  rtx_insn *seq = get_insns ();
> +  end_sequence ();
> +
> +  return saw_asm_flag ? seq : NULL;
> +}
> diff --git a/gcc/config/arm/arm-c.c b/gcc/config/arm/arm-c.c
> index 34695fa0112..c4485ce7af1 100644
> --- a/gcc/config/arm/arm-c.c
> +++ b/gcc/config/arm/arm-c.c
> @@ -122,6 +122,7 @@ arm_cpu_builtins (struct cpp_reader* pfile)
>     if (arm_arch_notm)
>       builtin_define ("__ARM_ARCH_ISA_ARM");
>     builtin_define ("__APCS_32__");
> +  builtin_define ("__GCC_ASM_FLAG_OUTPUTS__");
>   
>     def_or_undef_macro (pfile, "__thumb__", TARGET_THUMB);
>     def_or_undef_macro (pfile, "__thumb2__", TARGET_THUMB2);
> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
> index d996207853c..fea3882a2a6 100644
> --- a/gcc/config/arm/arm.c
> +++ b/gcc/config/arm/arm.c
> @@ -816,6 +816,9 @@ static const struct attribute_spec arm_attribute_table[] =
>   
>   #undef TARGET_CONSTANT_ALIGNMENT
>   #define TARGET_CONSTANT_ALIGNMENT arm_constant_alignment
> +
> +#undef TARGET_MD_ASM_ADJUST
> +#define TARGET_MD_ASM_ADJUST arm_md_asm_adjust
>   
>   /* Obstack for minipool constant handling.  */
>   static struct obstack minipool_obstack;
> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index 9db4f9b1d29..1c8ae0d5cd3 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -9771,6 +9771,45 @@ referenced within the assembler template via @code{%0} etc, as there's
>   no corresponding text in the assembly language.
>   
>   @table @asis
> +@item ARM
> +@itemx AArch64
> +The flag output constraints for the ARM family are of the form
> +@samp{=@@cc@var{cond}} where @var{cond} is one of the standard
> +conditions defined in the ARM ARM for @code{ConditionHolds}.
> +
> +@table @code
> +@item eq
> +Z flag set, or equal
> +@item ne
> +Z flag clear or not equal
> +@item cs
> +@itemx hs
> +C flag set or unsigned greater than equal
> +@item cc
> +@itemx lo
> +C flag clear or unsigned less than
> +@item mi
> +N flag set or ``minus''
> +@item pl
> +N flag clear or ``plus''
> +@item vs
> +V flag set or signed overflow
> +@item vc
> +V flag clear
> +@item hi
> +unsigned greater than
> +@item ls
> +unsigned less than equal
> +@item ge
> +signed greater than equal
> +@item lt
> +signed less than
> +@item gt
> +signed greater than
> +@item le
> +signed less than equal
> +@end table
> +
>   @item x86 family
>   The flag output constraints for the x86 family are of the form
>   @samp{=@@cc@var{cond}} where @var{cond} is one of the standard
>
Richard Earnshaw (lists) Nov. 14, 2019, 2:48 p.m. UTC | #2
On 14/11/2019 10:07, Richard Henderson wrote:
> Since all but a couple of lines is shared between the two targets,
> enable them both at once.
> 
> 	* config/arm/aarch-common-protos.h (arm_md_asm_adjust): Declare.
> 	* config/arm/aarch-common.c (arm_md_asm_adjust): New.
> 	* config/arm/arm-c.c (arm_cpu_builtins): Define
> 	__GCC_ASM_FLAG_OUTPUTS__.
> 	* config/arm/arm.c (TARGET_MD_ASM_ADJUST): New.
> 	* config/aarch64/aarch64-c.c (aarch64_define_unconditional_macros):
> 	Define __GCC_ASM_FLAG_OUTPUTS__.
> 	* config/aarch64/aarch64.c (TARGET_MD_ASM_ADJUST): New.
> 	* doc/extend.texi (FlagOutputOperands): Add documentation
> 	for ARM and AArch64.

In AArch64 when SVE is enabled, there are some additional condition 
names which are more suited for describing the way conditions are set by 
the SVE instructions.  Do you plan to support those as well?

R.

> ---
>   gcc/config/arm/aarch-common-protos.h |   6 ++
>   gcc/config/aarch64/aarch64-c.c       |   2 +
>   gcc/config/aarch64/aarch64.c         |   3 +
>   gcc/config/arm/aarch-common.c        | 136 +++++++++++++++++++++++++++
>   gcc/config/arm/arm-c.c               |   1 +
>   gcc/config/arm/arm.c                 |   3 +
>   gcc/doc/extend.texi                  |  39 ++++++++
>   7 files changed, 190 insertions(+)
> 
> diff --git a/gcc/config/arm/aarch-common-protos.h b/gcc/config/arm/aarch-common-protos.h
> index 3bf38a104f6..f15cf336e9d 100644
> --- a/gcc/config/arm/aarch-common-protos.h
> +++ b/gcc/config/arm/aarch-common-protos.h
> @@ -23,6 +23,8 @@
>   #ifndef GCC_AARCH_COMMON_PROTOS_H
>   #define GCC_AARCH_COMMON_PROTOS_H
>   
> +#include "hard-reg-set.h"
> +
>   extern int aarch_accumulator_forwarding (rtx_insn *, rtx_insn *);
>   extern bool aarch_rev16_p (rtx);
>   extern bool aarch_rev16_shleft_mask_imm_p (rtx, machine_mode);
> @@ -141,5 +143,9 @@ struct cpu_cost_table
>     const struct vector_cost_table vect;
>   };
>   
> +rtx_insn *
> +arm_md_asm_adjust (vec<rtx> &outputs, vec<rtx> &/*inputs*/,
> +		    vec<const char *> &constraints,
> +		    vec<rtx> &clobbers, HARD_REG_SET &clobbered_regs);
>   
>   #endif /* GCC_AARCH_COMMON_PROTOS_H */
> diff --git a/gcc/config/aarch64/aarch64-c.c b/gcc/config/aarch64/aarch64-c.c
> index 7c322ca0813..0af859f1c14 100644
> --- a/gcc/config/aarch64/aarch64-c.c
> +++ b/gcc/config/aarch64/aarch64-c.c
> @@ -69,6 +69,8 @@ aarch64_define_unconditional_macros (cpp_reader *pfile)
>     builtin_define ("__ARM_FEATURE_UNALIGNED");
>     builtin_define ("__ARM_PCS_AAPCS64");
>     builtin_define_with_int_value ("__ARM_SIZEOF_WCHAR_T", WCHAR_TYPE_SIZE / 8);
> +
> +  builtin_define ("__GCC_ASM_FLAG_OUTPUTS__");
>   }
>   
>   /* Undefine/redefine macros that depend on the current backend state and may
> diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
> index d2a3c7ef90a..9a5f27fea3a 100644
> --- a/gcc/config/aarch64/aarch64.c
> +++ b/gcc/config/aarch64/aarch64.c
> @@ -21933,6 +21933,9 @@ aarch64_libgcc_floating_mode_supported_p
>   #undef TARGET_STRICT_ARGUMENT_NAMING
>   #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
>   
> +#undef TARGET_MD_ASM_ADJUST
> +#define TARGET_MD_ASM_ADJUST arm_md_asm_adjust
> +
>   struct gcc_target targetm = TARGET_INITIALIZER;
>   
>   #include "gt-aarch64.h"
> diff --git a/gcc/config/arm/aarch-common.c b/gcc/config/arm/aarch-common.c
> index 965a07a43e3..760ef6c9c0a 100644
> --- a/gcc/config/arm/aarch-common.c
> +++ b/gcc/config/arm/aarch-common.c
> @@ -26,10 +26,16 @@
>   #include "config.h"
>   #include "system.h"
>   #include "coretypes.h"
> +#include "insn-modes.h"
>   #include "tm.h"
>   #include "rtl.h"
>   #include "rtl-iter.h"
>   #include "memmodel.h"
> +#include "diagnostic.h"
> +#include "tree.h"
> +#include "expr.h"
> +#include "function.h"
> +#include "emit-rtl.h"
>   
>   /* Return TRUE if X is either an arithmetic shift left, or
>      is a multiplication by a power of two.  */
> @@ -520,3 +526,133 @@ arm_mac_accumulator_is_mul_result (rtx producer, rtx consumer)
>             && !reg_overlap_mentioned_p (mul_result, mac_op0)
>             && !reg_overlap_mentioned_p (mul_result, mac_op1));
>   }
> +
> +/* Worker function for TARGET_MD_ASM_ADJUST.
> +   We implement asm flag outputs.  */
> +
> +rtx_insn *
> +arm_md_asm_adjust (vec<rtx> &outputs, vec<rtx> &/*inputs*/,
> +		    vec<const char *> &constraints,
> +		    vec<rtx> &/*clobbers*/, HARD_REG_SET &/*clobbered_regs*/)
> +{
> +  bool saw_asm_flag = false;
> +
> +  start_sequence ();
> +  for (unsigned i = 0, n = outputs.length (); i < n; ++i)
> +    {
> +      const char *con = constraints[i];
> +      if (strncmp (con, "=@cc", 4) != 0)
> +	continue;
> +      con += 4;
> +      if (strchr (con, ',') != NULL)
> +	{
> +	  error ("alternatives not allowed in %<asm%> flag output");
> +	  continue;
> +	}
> +
> +      machine_mode mode;
> +      rtx_code code;
> +      int con01 = 0;
> +
> +#define C(X, Y)  (unsigned char)(X) * 256 + (unsigned char)(Y)
> +
> +      /* All of the condition codes are two characters.  */
> +      if (con[0] != 0 && con[1] != 0 && con[2] == 0)
> +	con01 = C(con[0], con[1]);
> +
> +      switch (con01)
> +	{
> +	case C('c', 'c'):
> +	case C('l', 'o'):
> +	  mode = CC_Cmode, code = GEU;
> +	  break;
> +	case C('c', 's'):
> +	case C('h', 's'):
> +	  mode = CC_Cmode, code = LTU;
> +	  break;
> +	case C('e', 'q'):
> +	  mode = CC_NZmode, code = EQ;
> +	  break;
> +	case C('g', 'e'):
> +	  mode = CCmode, code = GE;
> +	  break;
> +	case C('g', 't'):
> +	  mode = CCmode, code = GT;
> +	  break;
> +	case C('h', 'i'):
> +	  mode = CCmode, code = GTU;
> +	  break;
> +	case C('l', 'e'):
> +	  mode = CCmode, code = LE;
> +	  break;
> +	case C('l', 's'):
> +	  mode = CCmode, code = LEU;
> +	  break;
> +	case C('l', 't'):
> +	  mode = CCmode, code = LT;
> +	  break;
> +	case C('m', 'i'):
> +	  mode = CC_NZmode, code = LT;
> +	  break;
> +	case C('n', 'e'):
> +	  mode = CC_NZmode, code = NE;
> +	  break;
> +	case C('p', 'l'):
> +	  mode = CC_NZmode, code = GE;
> +	  break;
> +	case C('v', 'c'):
> +	  mode = CC_Vmode, code = EQ;
> +	  break;
> +	case C('v', 's'):
> +	  mode = CC_Vmode, code = NE;
> +	  break;
> +	default:
> +	  error ("unknown %<asm%> flag output %qs", constraints[i]);
> +	  continue;
> +	}
> +
> +#undef C
> +
> +      rtx dest = outputs[i];
> +      machine_mode dest_mode = GET_MODE (dest);
> +      if (!SCALAR_INT_MODE_P (dest_mode))
> +	{
> +	  error ("invalid type for %<asm%> flag output");
> +	  continue;
> +	}
> +
> +      if (!saw_asm_flag)
> +	{
> +	  /* This is the first asm flag output.  Here we put the flags
> +	     register in as the real output and adjust the condition to
> +	     allow it.  */
> +	  constraints[i] = "=c";
> +	  outputs[i] = gen_rtx_REG (CCmode, CC_REGNUM);
> +	  saw_asm_flag = true;
> +	}
> +      else
> +	{
> +	  /* We don't need the flags register as output twice.  */
> +	  constraints[i] = "=X";
> +	  outputs[i] = gen_rtx_SCRATCH (word_mode);
> +	}
> +
> +      rtx x = gen_rtx_REG (mode, CC_REGNUM);
> +      x = gen_rtx_fmt_ee (code, word_mode, x, const0_rtx);
> +
> +      if (dest_mode == word_mode)
> +	emit_insn (gen_rtx_SET (dest, x));
> +      else
> +	{
> +	  rtx tmp = gen_reg_rtx (word_mode);
> +	  emit_insn (gen_rtx_SET (tmp, x));
> +
> +	  tmp = convert_modes (dest_mode, word_mode, tmp, true);
> +	  emit_move_insn (dest, tmp);
> +	}
> +    }
> +  rtx_insn *seq = get_insns ();
> +  end_sequence ();
> +
> +  return saw_asm_flag ? seq : NULL;
> +}
> diff --git a/gcc/config/arm/arm-c.c b/gcc/config/arm/arm-c.c
> index 34695fa0112..c4485ce7af1 100644
> --- a/gcc/config/arm/arm-c.c
> +++ b/gcc/config/arm/arm-c.c
> @@ -122,6 +122,7 @@ arm_cpu_builtins (struct cpp_reader* pfile)
>     if (arm_arch_notm)
>       builtin_define ("__ARM_ARCH_ISA_ARM");
>     builtin_define ("__APCS_32__");
> +  builtin_define ("__GCC_ASM_FLAG_OUTPUTS__");
>   
>     def_or_undef_macro (pfile, "__thumb__", TARGET_THUMB);
>     def_or_undef_macro (pfile, "__thumb2__", TARGET_THUMB2);
> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
> index d996207853c..fea3882a2a6 100644
> --- a/gcc/config/arm/arm.c
> +++ b/gcc/config/arm/arm.c
> @@ -816,6 +816,9 @@ static const struct attribute_spec arm_attribute_table[] =
>   
>   #undef TARGET_CONSTANT_ALIGNMENT
>   #define TARGET_CONSTANT_ALIGNMENT arm_constant_alignment
> +
> +#undef TARGET_MD_ASM_ADJUST
> +#define TARGET_MD_ASM_ADJUST arm_md_asm_adjust
>   
>   /* Obstack for minipool constant handling.  */
>   static struct obstack minipool_obstack;
> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index 9db4f9b1d29..1c8ae0d5cd3 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -9771,6 +9771,45 @@ referenced within the assembler template via @code{%0} etc, as there's
>   no corresponding text in the assembly language.
>   
>   @table @asis
> +@item ARM
> +@itemx AArch64
> +The flag output constraints for the ARM family are of the form
> +@samp{=@@cc@var{cond}} where @var{cond} is one of the standard
> +conditions defined in the ARM ARM for @code{ConditionHolds}.
> +
> +@table @code
> +@item eq
> +Z flag set, or equal
> +@item ne
> +Z flag clear or not equal
> +@item cs
> +@itemx hs
> +C flag set or unsigned greater than equal
> +@item cc
> +@itemx lo
> +C flag clear or unsigned less than
> +@item mi
> +N flag set or ``minus''
> +@item pl
> +N flag clear or ``plus''
> +@item vs
> +V flag set or signed overflow
> +@item vc
> +V flag clear
> +@item hi
> +unsigned greater than
> +@item ls
> +unsigned less than equal
> +@item ge
> +signed greater than equal
> +@item lt
> +signed less than
> +@item gt
> +signed greater than
> +@item le
> +signed less than equal
> +@end table
> +
>   @item x86 family
>   The flag output constraints for the x86 family are of the form
>   @samp{=@@cc@var{cond}} where @var{cond} is one of the standard
>
Richard Henderson Nov. 14, 2019, 3:06 p.m. UTC | #3
On 11/14/19 3:39 PM, Richard Earnshaw (lists) wrote:
> Not had a chance to look at this in detail, but I don't see any support for
> 
> 1) Thumb1 where we do not expose the condition codes at all
> 2) Thumb2 where we need IT instructions along-side the conditional instructions
> themselves.
> 
> How have you tested this for those targets?

I tested aarch64-linux and arm-elf-eabi (I'm currently 8 time zones away from
my arm-linux-eabihf box, so using sim).

I didn't know about the thumb1 restriction.  I had assumed somehow that we'd
just use branch insns to form whatever cstore* is required.  I suppose it's
easy enough to generate an error/sorry for asm-flags in thumb1 mode.

As for thumb2, correct behaviour comes from the existing cstore* patterns, and
the testsuite need not check for IT specifically because unified asm syntax
says that the insns that are conditional under the IT should still bear the
conditions themselves.

I presume I can test both of these cases with arm-elf-eabi + -mthumb{1,2}?


r~
Richard Henderson Nov. 14, 2019, 3:11 p.m. UTC | #4
On 11/14/19 3:48 PM, Richard Earnshaw (lists) wrote:
> On 14/11/2019 10:07, Richard Henderson wrote:
>> Since all but a couple of lines is shared between the two targets,
>> enable them both at once.
>>
>>     * config/arm/aarch-common-protos.h (arm_md_asm_adjust): Declare.
>>     * config/arm/aarch-common.c (arm_md_asm_adjust): New.
>>     * config/arm/arm-c.c (arm_cpu_builtins): Define
>>     __GCC_ASM_FLAG_OUTPUTS__.
>>     * config/arm/arm.c (TARGET_MD_ASM_ADJUST): New.
>>     * config/aarch64/aarch64-c.c (aarch64_define_unconditional_macros):
>>     Define __GCC_ASM_FLAG_OUTPUTS__.
>>     * config/aarch64/aarch64.c (TARGET_MD_ASM_ADJUST): New.
>>     * doc/extend.texi (FlagOutputOperands): Add documentation
>>     for ARM and AArch64.
> 
> In AArch64 when SVE is enabled, there are some additional condition names which
> are more suited for describing the way conditions are set by the SVE
> instructions.  Do you plan to support those as well?

I did not, no.

I read the acle spec once at the beginning of the year, and vaguely recall that
it already covers pretty much all one wants to do.  I haven't given much
thought to sve in inline asm since.

I suppose I can add them if they're thought important.


r~
Richard Earnshaw (lists) Nov. 14, 2019, 3:16 p.m. UTC | #5
On 14/11/2019 15:06, Richard Henderson wrote:
> On 11/14/19 3:39 PM, Richard Earnshaw (lists) wrote:
>> Not had a chance to look at this in detail, but I don't see any support for
>>
>> 1) Thumb1 where we do not expose the condition codes at all
>> 2) Thumb2 where we need IT instructions along-side the conditional instructions
>> themselves.
>>
>> How have you tested this for those targets?
> 
> I tested aarch64-linux and arm-elf-eabi (I'm currently 8 time zones away from
> my arm-linux-eabihf box, so using sim).
> 
> I didn't know about the thumb1 restriction.  I had assumed somehow that we'd
> just use branch insns to form whatever cstore* is required.  I suppose it's
> easy enough to generate an error/sorry for asm-flags in thumb1 mode.

I suggest we just suppress the __GCC_ASM_FLAG_OUTPUTS__ define if 
targetting thumb1.  In the tests, we then just make the code PASS in 
that case.
> 
> As for thumb2, correct behaviour comes from the existing cstore* patterns, and
> the testsuite need not check for IT specifically because unified asm syntax
> says that the insns that are conditional under the IT should still bear the
> conditions themselves.
> 
> I presume I can test both of these cases with arm-elf-eabi + -mthumb{1,2}?

Not quite, selection of thumb/thumb1 is controlled by the architecture 
(or the cpu that causes the architecture chosen).  There are several 
helpers in target-supports.exp to help with testing if the selected 
architecture has thumb/thumb2/neither as appropriate.

R.

> 
> 
> r~
>

Patch
diff mbox series

diff --git a/gcc/config/arm/aarch-common-protos.h b/gcc/config/arm/aarch-common-protos.h
index 3bf38a104f6..f15cf336e9d 100644
--- a/gcc/config/arm/aarch-common-protos.h
+++ b/gcc/config/arm/aarch-common-protos.h
@@ -23,6 +23,8 @@ 
 #ifndef GCC_AARCH_COMMON_PROTOS_H
 #define GCC_AARCH_COMMON_PROTOS_H
 
+#include "hard-reg-set.h"
+
 extern int aarch_accumulator_forwarding (rtx_insn *, rtx_insn *);
 extern bool aarch_rev16_p (rtx);
 extern bool aarch_rev16_shleft_mask_imm_p (rtx, machine_mode);
@@ -141,5 +143,9 @@  struct cpu_cost_table
   const struct vector_cost_table vect;
 };
 
+rtx_insn *
+arm_md_asm_adjust (vec<rtx> &outputs, vec<rtx> &/*inputs*/,
+		    vec<const char *> &constraints,
+		    vec<rtx> &clobbers, HARD_REG_SET &clobbered_regs);
 
 #endif /* GCC_AARCH_COMMON_PROTOS_H */
diff --git a/gcc/config/aarch64/aarch64-c.c b/gcc/config/aarch64/aarch64-c.c
index 7c322ca0813..0af859f1c14 100644
--- a/gcc/config/aarch64/aarch64-c.c
+++ b/gcc/config/aarch64/aarch64-c.c
@@ -69,6 +69,8 @@  aarch64_define_unconditional_macros (cpp_reader *pfile)
   builtin_define ("__ARM_FEATURE_UNALIGNED");
   builtin_define ("__ARM_PCS_AAPCS64");
   builtin_define_with_int_value ("__ARM_SIZEOF_WCHAR_T", WCHAR_TYPE_SIZE / 8);
+
+  builtin_define ("__GCC_ASM_FLAG_OUTPUTS__");
 }
 
 /* Undefine/redefine macros that depend on the current backend state and may
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index d2a3c7ef90a..9a5f27fea3a 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -21933,6 +21933,9 @@  aarch64_libgcc_floating_mode_supported_p
 #undef TARGET_STRICT_ARGUMENT_NAMING
 #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
 
+#undef TARGET_MD_ASM_ADJUST
+#define TARGET_MD_ASM_ADJUST arm_md_asm_adjust
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-aarch64.h"
diff --git a/gcc/config/arm/aarch-common.c b/gcc/config/arm/aarch-common.c
index 965a07a43e3..760ef6c9c0a 100644
--- a/gcc/config/arm/aarch-common.c
+++ b/gcc/config/arm/aarch-common.c
@@ -26,10 +26,16 @@ 
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "insn-modes.h"
 #include "tm.h"
 #include "rtl.h"
 #include "rtl-iter.h"
 #include "memmodel.h"
+#include "diagnostic.h"
+#include "tree.h"
+#include "expr.h"
+#include "function.h"
+#include "emit-rtl.h"
 
 /* Return TRUE if X is either an arithmetic shift left, or
    is a multiplication by a power of two.  */
@@ -520,3 +526,133 @@  arm_mac_accumulator_is_mul_result (rtx producer, rtx consumer)
           && !reg_overlap_mentioned_p (mul_result, mac_op0)
           && !reg_overlap_mentioned_p (mul_result, mac_op1));
 }
+
+/* Worker function for TARGET_MD_ASM_ADJUST.
+   We implement asm flag outputs.  */
+
+rtx_insn *
+arm_md_asm_adjust (vec<rtx> &outputs, vec<rtx> &/*inputs*/,
+		    vec<const char *> &constraints,
+		    vec<rtx> &/*clobbers*/, HARD_REG_SET &/*clobbered_regs*/)
+{
+  bool saw_asm_flag = false;
+
+  start_sequence ();
+  for (unsigned i = 0, n = outputs.length (); i < n; ++i)
+    {
+      const char *con = constraints[i];
+      if (strncmp (con, "=@cc", 4) != 0)
+	continue;
+      con += 4;
+      if (strchr (con, ',') != NULL)
+	{
+	  error ("alternatives not allowed in %<asm%> flag output");
+	  continue;
+	}
+
+      machine_mode mode;
+      rtx_code code;
+      int con01 = 0;
+
+#define C(X, Y)  (unsigned char)(X) * 256 + (unsigned char)(Y)
+
+      /* All of the condition codes are two characters.  */
+      if (con[0] != 0 && con[1] != 0 && con[2] == 0)
+	con01 = C(con[0], con[1]);
+
+      switch (con01)
+	{
+	case C('c', 'c'):
+	case C('l', 'o'):
+	  mode = CC_Cmode, code = GEU;
+	  break;
+	case C('c', 's'):
+	case C('h', 's'):
+	  mode = CC_Cmode, code = LTU;
+	  break;
+	case C('e', 'q'):
+	  mode = CC_NZmode, code = EQ;
+	  break;
+	case C('g', 'e'):
+	  mode = CCmode, code = GE;
+	  break;
+	case C('g', 't'):
+	  mode = CCmode, code = GT;
+	  break;
+	case C('h', 'i'):
+	  mode = CCmode, code = GTU;
+	  break;
+	case C('l', 'e'):
+	  mode = CCmode, code = LE;
+	  break;
+	case C('l', 's'):
+	  mode = CCmode, code = LEU;
+	  break;
+	case C('l', 't'):
+	  mode = CCmode, code = LT;
+	  break;
+	case C('m', 'i'):
+	  mode = CC_NZmode, code = LT;
+	  break;
+	case C('n', 'e'):
+	  mode = CC_NZmode, code = NE;
+	  break;
+	case C('p', 'l'):
+	  mode = CC_NZmode, code = GE;
+	  break;
+	case C('v', 'c'):
+	  mode = CC_Vmode, code = EQ;
+	  break;
+	case C('v', 's'):
+	  mode = CC_Vmode, code = NE;
+	  break;
+	default:
+	  error ("unknown %<asm%> flag output %qs", constraints[i]);
+	  continue;
+	}
+
+#undef C
+
+      rtx dest = outputs[i];
+      machine_mode dest_mode = GET_MODE (dest);
+      if (!SCALAR_INT_MODE_P (dest_mode))
+	{
+	  error ("invalid type for %<asm%> flag output");
+	  continue;
+	}
+
+      if (!saw_asm_flag)
+	{
+	  /* This is the first asm flag output.  Here we put the flags
+	     register in as the real output and adjust the condition to
+	     allow it.  */
+	  constraints[i] = "=c";
+	  outputs[i] = gen_rtx_REG (CCmode, CC_REGNUM);
+	  saw_asm_flag = true;
+	}
+      else
+	{
+	  /* We don't need the flags register as output twice.  */
+	  constraints[i] = "=X";
+	  outputs[i] = gen_rtx_SCRATCH (word_mode);
+	}
+
+      rtx x = gen_rtx_REG (mode, CC_REGNUM);
+      x = gen_rtx_fmt_ee (code, word_mode, x, const0_rtx);
+
+      if (dest_mode == word_mode)
+	emit_insn (gen_rtx_SET (dest, x));
+      else
+	{
+	  rtx tmp = gen_reg_rtx (word_mode);
+	  emit_insn (gen_rtx_SET (tmp, x));
+
+	  tmp = convert_modes (dest_mode, word_mode, tmp, true);
+	  emit_move_insn (dest, tmp);
+	}
+    }
+  rtx_insn *seq = get_insns ();
+  end_sequence ();
+
+  return saw_asm_flag ? seq : NULL;
+}
diff --git a/gcc/config/arm/arm-c.c b/gcc/config/arm/arm-c.c
index 34695fa0112..c4485ce7af1 100644
--- a/gcc/config/arm/arm-c.c
+++ b/gcc/config/arm/arm-c.c
@@ -122,6 +122,7 @@  arm_cpu_builtins (struct cpp_reader* pfile)
   if (arm_arch_notm)
     builtin_define ("__ARM_ARCH_ISA_ARM");
   builtin_define ("__APCS_32__");
+  builtin_define ("__GCC_ASM_FLAG_OUTPUTS__");
 
   def_or_undef_macro (pfile, "__thumb__", TARGET_THUMB);
   def_or_undef_macro (pfile, "__thumb2__", TARGET_THUMB2);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index d996207853c..fea3882a2a6 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -816,6 +816,9 @@  static const struct attribute_spec arm_attribute_table[] =
 
 #undef TARGET_CONSTANT_ALIGNMENT
 #define TARGET_CONSTANT_ALIGNMENT arm_constant_alignment
+
+#undef TARGET_MD_ASM_ADJUST
+#define TARGET_MD_ASM_ADJUST arm_md_asm_adjust
 
 /* Obstack for minipool constant handling.  */
 static struct obstack minipool_obstack;
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 9db4f9b1d29..1c8ae0d5cd3 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -9771,6 +9771,45 @@  referenced within the assembler template via @code{%0} etc, as there's
 no corresponding text in the assembly language.
 
 @table @asis
+@item ARM
+@itemx AArch64
+The flag output constraints for the ARM family are of the form
+@samp{=@@cc@var{cond}} where @var{cond} is one of the standard
+conditions defined in the ARM ARM for @code{ConditionHolds}.
+
+@table @code
+@item eq
+Z flag set, or equal
+@item ne
+Z flag clear or not equal
+@item cs
+@itemx hs
+C flag set or unsigned greater than equal
+@item cc
+@itemx lo
+C flag clear or unsigned less than
+@item mi
+N flag set or ``minus''
+@item pl
+N flag clear or ``plus''
+@item vs
+V flag set or signed overflow
+@item vc
+V flag clear
+@item hi
+unsigned greater than
+@item ls
+unsigned less than equal
+@item ge
+signed greater than equal
+@item lt
+signed less than
+@item gt
+signed greater than
+@item le
+signed less than equal
+@end table
+
 @item x86 family
 The flag output constraints for the x86 family are of the form
 @samp{=@@cc@var{cond}} where @var{cond} is one of the standard