claudiu.zissulescu-iancule...@oracle.com writes:
> [...]
>  /* Implement TARGET_MEMTAG_CAN_TAG_ADDRESSES.  Here we tell the rest of the
>     compiler that we automatically ignore the top byte of our pointers, which
> -   allows using -fsanitize=hwaddress.  */
> +   allows using -fsanitize=hwaddress.  In case of -fsanitize=memtag, we
> +   additionally ensure that target supports MEMTAG insns.  */
>  bool
>  aarch64_can_tag_addresses ()
>  {
> +  if (memtag_sanitize_p ())
> +    return !TARGET_ILP32 && TARGET_MEMTAG;
>    return !TARGET_ILP32;
>  }
>  
> +/* Implement TARGET_MEMTAG_TAG_BITSIZE.  */
> +unsigned char
> +aarch64_memtag_tag_bitsize ()
> +{
> +  if (memtag_sanitize_p ())
> +    return AARCH64_MEMTAG_TAG_BITSIZE;
> +  return default_memtag_tag_bitsize ();
> +}
> +
> +/* Implement TARGET_MEMTAG_GRANULE_SIZE.  */
> +unsigned char
> +aarch64_memtag_granule_size ()
> +{
> +  if (memtag_sanitize_p ())
> +    return AARCH64_MEMTAG_GRANULE_SIZE;
> +  return default_memtag_granule_size ();
> +}
> +
> +/* Implement TARGET_MEMTAG_INSERT_RANDOM_TAG.  */
> +rtx
> +aarch64_memtag_insert_random_tag (rtx untagged, rtx target)
> +{
> +  if (memtag_sanitize_p ())
> +    {
> +      insn_code icode = CODE_FOR_gmi;
> +      expand_operand ops_gmi[3];
> +      rtx tmp = gen_reg_rtx (Pmode);
> +      create_output_operand (&ops_gmi[0], tmp, Pmode);
> +      create_input_operand  (&ops_gmi[1], untagged, Pmode);
> +      create_integer_operand  (&ops_gmi[2], 0);
> +      expand_insn (icode, 3, ops_gmi);
> +
> +      icode = CODE_FOR_irg;
> +      expand_operand ops_irg[3];
> +      create_output_operand (&ops_irg[0], target, Pmode);
> +      create_input_operand  (&ops_irg[1], untagged, Pmode);
> +      create_input_operand  (&ops_irg[2], ops_gmi[0].value, Pmode);
> +      expand_insn (icode, 3, ops_irg);
> +      return ops_irg[0].value;
> +    }
> +  else
> +    return default_memtag_insert_random_tag (untagged, target);
> +}
> +
> +/* Implement TARGET_MEMTAG_ADD_TAG.  */
> +rtx
> +aarch64_memtag_add_tag (rtx base, poly_int64 offset, uint8_t tag_offset)
> +{
> +  rtx target = NULL;
> +  poly_int64 addr_offset = offset;
> +  rtx offset_rtx = gen_int_mode (addr_offset, DImode);

This should only be done for the non-default path.  Same below.

> +
> +  if (!memtag_sanitize_p () || tag_offset == 0)
> +    return default_memtag_add_tag (base, offset, tag_offset);

It would be good to use a consistent style about whether to exit
early for !memtag_sanitize_p or use:

  if (memtag_sanitizie_p ())
    ...
  else
    ...default...;

The former seems to be the general style used in GCC.  Same below.

> [...]
> diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
> index bade8af7997..472d4e07385 100644
> --- a/gcc/config/aarch64/aarch64.md
> +++ b/gcc/config/aarch64/aarch64.md
> @@ -8563,46 +8563,49 @@ (define_insn "aarch64_rndrrs"
>  ;; Memory Tagging Extension (MTE) instructions.
>  
>  (define_insn "irg"
> -  [(set (match_operand:DI 0 "register_operand" "=rk")
> +  [(set (match_operand:DI 0 "register_operand")
>       (ior:DI
> -      (and:DI (match_operand:DI 1 "register_operand" "rk")
> +      (and:DI (match_operand:DI 1 "register_operand")
>                (const_int MEMTAG_TAG_MASK)) ;; 0xf0ff...
> -      (ashift:DI (unspec:QI [(match_operand:DI 2 "register_operand" "r")]
> +      (ashift:DI (unspec:QI [(match_operand:DI 2 "aarch64_reg_or_zero")]
>                    UNSPEC_GEN_TAG_RND)
>                   (const_int 56))))]
>    "TARGET_MEMTAG"
> -  "irg\\t%0, %1, %2"
> -  [(set_attr "type" "memtag")]
> +  {@ [ cons: =0, 1, 2 ; attrs: type ]
> +     [ rk      , rk, r  ; memtag ] irg\\t%0, %1, %2
> +     [ rk      , rk, Z  ; memtag ] irg\\t%0, %1
> +  }
>  )
>  
>  (define_insn "gmi"
> -  [(set (match_operand:DI 0 "register_operand" "=r")
> -     (ior:DI (ashift:DI
> -              (const_int 1)
> -              (and:QI (lshiftrt:DI
> -                       (match_operand:DI 1 "register_operand" "rk")
> -                       (const_int 56)) (const_int 15)))
> -             (match_operand:DI 2 "register_operand" "r")))]
> +  [(set (match_operand:DI 0 "register_operand")
> +     (ior:DI
> +      (unspec:DI [(match_operand:DI 1 "register_operand")]
> +                 UNSPEC_GEN_TAG)

UNSPEC_GEN_TAG is for the ADDG case and takes two operands (previously:
the original tag and the offset, now: a pointer with the original tag
and the offset).

I suppose if we don't use UNSPEC_GEN_TAG here, we won't match and use
GMI when operand 2 is zero.  Is that why you changed this pattern too?
If so, I think we should make it:

         (unspec:DI [(match_operand:DI 1 "register_operand")
                     (const_int 0)]
                    UNSPEC_GEN_TAG)

instead.

> +      (match_operand:DI 2 "aarch64_reg_or_zero")))]
>    "TARGET_MEMTAG"
> -  "gmi\\t%0, %1, %2"
> -  [(set_attr "type" "memtag")]
> +  {@ [ cons: =0, 1, 2 ; attrs: type ]
> +     [ r       , rk, r  ; memtag ] gmi\\t%0, %1, %2
> +     [ r       , rk, Z  ; memtag ] gmi\\t%0, %1, xzr
> +  }

There's no need to separate these alternatives out.  We can use rZ
as the constraint and %x2 as the output operand.

>  )
>  
>  (define_insn "addg"
> -  [(set (match_operand:DI 0 "register_operand" "=rk")
> +  [(set (match_operand:DI 0 "register_operand")
>       (ior:DI
> -      (and:DI (plus:DI (match_operand:DI 1 "register_operand" "rk")
> -                       (match_operand:DI 2 "aarch64_granule16_uimm6" "i"))
> -              (const_int -1080863910568919041)) ;; 0xf0ff...
> +      (and:DI (plus:DI (match_operand:DI 1 "register_operand")
> +                       (match_operand:DI 2 "aarch64_granule16_imm6"))
> +              (const_int MEMTAG_TAG_MASK))
>        (ashift:DI
> -       (unspec:QI
> -        [(and:QI (lshiftrt:DI (match_dup 1) (const_int 56)) (const_int 15))
> -         (match_operand:QI 3 "aarch64_memtag_tag_offset" "i")]
> -        UNSPEC_GEN_TAG)
> +           (unspec:DI [(match_dup 1)
> +                       (match_operand:QI 3 "aarch64_memtag_tag_offset")]
> +                       UNSPEC_GEN_TAG)
>         (const_int 56))))]
>    "TARGET_MEMTAG"
> -  "addg\\t%0, %1, #%2, #%3"
> -  [(set_attr "type" "memtag")]
> +  {@ [ cons: =0 , 1  , 2 , 3 ; attrs: type ]
> +     [ rk       , rk , Uag , Utg ; memtag   ] addg\t%0, %1, #%2, #%3
> +     [ rk       , rk , Ung , Utg ; memtag   ] subg\t%0, %1, #%n2, #%3
> +  }
>  )
>  
>  (define_insn "subp"
> @@ -8636,17 +8639,40 @@ (define_insn "ldg"
>  ;; STG doesn't align the address but aborts with alignment fault
>  ;; when the address is not 16-byte aligned.
>  (define_insn "stg"
> -  [(set (mem:QI (unspec:DI
> -      [(plus:DI (match_operand:DI 1 "register_operand" "rk")
> -                (match_operand:DI 2 "aarch64_granule16_simm9" "i"))]
> -      UNSPEC_TAG_SPACE))
> -     (and:QI (lshiftrt:DI (match_operand:DI 0 "register_operand" "rk")
> -                          (const_int 56)) (const_int 15)))]
> -  "TARGET_MEMTAG"
> -  "stg\\t%0, [%1, #%2]"
> +  [(set (match_operand:TI 0 "aarch64_granule16_memory_operand" "=Umg")
> +      (unspec:TI
> +        [(match_operand:TI 1 "aarch64_granule16_memory_operand" "Umg")
> +         (match_operand:DI 2 "register_operand" "rk")]
> +        UNSPEC_TAG_SPACE))]
> +  "TARGET_MEMTAG && aarch64_check_memtag_ops (operands[0], operands[1])"
> +  "stg\\t%2, %0"
> +  [(set_attr "type" "memtag")]
> +)

In the previous reviews, I'd suggested we use things like:

(set (match_operand:TI 0 "aarch64_granule_memory_operand" "+Umg")
     (unspec_volatile:TI
       [(match_dup 0)
        (match_operand:DI 1 "register_operand" "rk")]
       UNSPECV...))

for the STG patterns.  Does that not work?  I remember there was some
follow-up discussion about the post-increment case, but I thought the
plan had been to use a separate pattern for those.

(Sorry if I'm misremembering, been a while since the last series.)

The problem with the pattern in the patch is that operands 0 and 1's
predicates and constraints treat the operands as entirely separate.
aarch64_check_memtag_ops would be applied during insn recognition but
it would have no effect on (for example) register allocation.

That said... I wonder if it would work to drop the aarch64_check_memtag_ops
condition and instead use something like:

  return (GET_RTX_CLASS (GET_CODE (XEXP (operands[1], 0))) == RTX_AUTOINC
          ? "stg\\t%2, %1"
          : "stg\\t%2, %0");

We know that operands 0 and 1 started out as the same address value and
it would be invalid for any later pass to change that value (rather than
the way that the value is computed).

I don't remember seeing that RTX_AUTOINC pattern used before, and it
feels a bit underhand, but I can't immediately think of a reason why
it's wrong in principle.

The unspec must be unspec_volatile though, for the reason in the
previous review:

  The unspec_volatile should ensure that nothing tries to remove the
  store as dead (which would especially be a problem when clearing tags).

ISTR there was an issue about whether the unspec_volatile would
prevent autoinc.  If so, we should teach autoinc not to skip these
particular instructions (using a target hook if necessary, as previously
mentioned).

> +
> +;; ST2G updates allocation tags for two memory granules (i.e. 32 bytes) at
> +;; once, without zero initialization.
> +(define_insn "st2g"
> +  [(set (match_operand:OI 0 "aarch64_granule16_memory_operand" "=Umg")
> +      (unspec:OI
> +        [(match_operand:OI 1 "aarch64_granule16_memory_operand" "Umg")
> +         (match_operand:DI 2 "register_operand" "rk")]
> +        UNSPEC_TAG_SPACE))]
> +  "TARGET_MEMTAG && aarch64_check_memtag_ops (operands[0], operands[1])"
> +  "st2g\\t%2, %0"
>    [(set_attr "type" "memtag")]
>  )
>  
> +(define_expand "tag_memory"
> +  [(match_operand:DI 0 "general_operand" "")
> +   (match_operand:DI 1 "nonmemory_operand" "")
> +   (match_operand:DI 2 "nonmemory_operand" "")]
> +  ""
> +  "
> +{
> +  aarch64_expand_tag_memory (operands[0], operands[1], operands[2]);
> +  DONE;
> +}")
> +
>  ;; Load/Store 64-bit (LS64) instructions.
>  (define_insn "ld64b"
>    [(set (match_operand:V8DI 0 "register_operand" "=r")
> diff --git a/gcc/config/aarch64/constraints.md 
> b/gcc/config/aarch64/constraints.md
> index dc1925dfb6c..ac64b4fb228 100644
> --- a/gcc/config/aarch64/constraints.md
> +++ b/gcc/config/aarch64/constraints.md
> @@ -352,6 +352,12 @@ (define_memory_constraint "Ump"
>         (match_test "aarch64_legitimate_address_p (GET_MODE (op), XEXP (op, 
> 0),
>                                                 true, ADDR_QUERY_LDP_STP)")))
>  
> +(define_memory_constraint "Umg"
> +  "@internal
> +  A memory address for MTE load/store tag operation."
> +  (and (match_code "mem")
> +       (match_test "aarch64_granule16_memory_address_p (op)")))
> +
>  ;; Used for storing or loading pairs in an AdvSIMD register using an STP/LDP
>  ;; as a vector-concat.  The address mode uses the same constraints as if it
>  ;; were for a single value.
> @@ -606,6 +612,26 @@ (define_address_constraint "Dp"
>   An address valid for a prefetch instruction."
>   (match_test "aarch64_address_valid_for_prefetch_p (op, true)"))
>  
> +(define_constraint "Uag"
> +  "@internal
> +  A constant that can be used as address offset for an ADDG operation."
> +  (and (match_code "const_int")
> +       (match_test "IN_RANGE (ival, 0, 1008)
> +                 && !(ival & 0xf)")))
> +
> +(define_constraint "Ung"
> +  "@internal
> +  A constant that can be used as address offset for an SUBG operation (once
> +  negated)."
> +  (and (match_code "const_int")
> +       (match_test "IN_RANGE (ival, -1024, -1)
> +                 && !(ival & 0xf)")))
> +
> +(define_constraint "Utg"
> +  "@internal
> +  A constant that can be used as tag offset for an ADDG/SUBG operation."
> +  (match_operand 0 "aarch64_memtag_tag_offset"))

There's no need for this constraint, since the ADDG operand uses
aarch64_memtag_tag_offset as the predicate.  The constraints for
operand 3 can just be blank.

Thanks,
Richard

> +
>  (define_constraint "vgb"
>    "@internal
>     A constraint that matches an immediate offset valid for SVE LD1B
> diff --git a/gcc/config/aarch64/predicates.md 
> b/gcc/config/aarch64/predicates.md
> index 32056daf329..0a68b3638bc 100644
> --- a/gcc/config/aarch64/predicates.md
> +++ b/gcc/config/aarch64/predicates.md
> @@ -1061,13 +1061,20 @@ (define_predicate 
> "aarch64_bytes_per_sve_vector_operand"
>         (match_test "known_eq (wi::to_poly_wide (op, mode),
>                             BYTES_PER_SVE_VECTOR)")))
>  
> +;; The uimm4 field is a 4-bit field that only accepts immediates in the
> +;; range 0..15.
>  (define_predicate "aarch64_memtag_tag_offset"
>    (and (match_code "const_int")
> -       (match_test "IN_RANGE (INTVAL (op), 0, 15)")))
> +       (match_test "UINTVAL (op) <= 15")))
> +
> +(define_predicate "aarch64_granule16_memory_operand"
> +  (and (match_test "TARGET_MEMTAG")
> +       (match_code "mem")
> +       (match_test "aarch64_granule16_memory_address_p (op)")))
>  
> -(define_predicate "aarch64_granule16_uimm6"
> +(define_predicate "aarch64_granule16_imm6"
>    (and (match_code "const_int")
> -       (match_test "IN_RANGE (INTVAL (op), 0, 1008)
> +       (match_test "IN_RANGE (INTVAL (op), -1024, 1008)
>                   && !(INTVAL (op) & 0xf)")))
>  
>  (define_predicate "aarch64_granule16_simm9"
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index d8f11201361..c073ad3f303 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -18176,8 +18176,10 @@ for a list of supported options.
>  The option cannot be combined with @option{-fsanitize=thread} or
>  @option{-fsanitize=hwaddress}.  Note that the only targets
>  @option{-fsanitize=hwaddress} is currently supported on are x86-64
> -(only with @code{-mlam=u48} or @code{-mlam=u57} options) and AArch64,
> -in both cases only in ABIs with 64-bit pointers.
> +(only with @code{-mlam=u48} or @code{-mlam=u57} options) and AArch64, in both
> +cases only in ABIs with 64-bit pointers.  Similarly,
> +@option{-fsanitize=memtag-stack} is currently only supported on AArch64 ABIs
> +with 64-bit pointers.
>  
>  When compiling with @option{-fsanitize=address}, you should also
>  use @option{-g} to produce more meaningful output.
> diff --git a/gcc/testsuite/gcc.target/aarch64/acle/memtag_1.c 
> b/gcc/testsuite/gcc.target/aarch64/acle/memtag_1.c
> index f8368690032..e94a2220fe3 100644
> --- a/gcc/testsuite/gcc.target/aarch64/acle/memtag_1.c
> +++ b/gcc/testsuite/gcc.target/aarch64/acle/memtag_1.c
> @@ -54,9 +54,9 @@ test_memtag_6 (void *p)
>    __arm_mte_set_tag (p);
>  }
>  
> -/* { dg-final { scan-assembler-times {irg\tx..?, x..?, x..?\n} 1 } } */
> +/* { dg-final { scan-assembler-times {irg\tx..?, x..?\n} 1 } } */
>  /* { dg-final { scan-assembler-times {gmi\tx..?, x..?, x..?\n} 1 } } */
>  /* { dg-final { scan-assembler-times {subp\tx..?, x..?, x..?\n} 1 } } */
>  /* { dg-final { scan-assembler-times {addg\tx..?, x..?, #0, #1\n} 1 } } */
>  /* { dg-final { scan-assembler-times {ldg\tx..?, \[x..?, #0\]\n} 1 } } */
> -/* { dg-final { scan-assembler-times {stg\tx..?, \[x..?, #0\]\n} 1 } } */
> \ No newline at end of file
> +/* { dg-final { scan-assembler-times {stg\tx..?, \[x..?\]\n} 1 } } */

Reply via email to