[GCC16,RFC,V2 03/14] aarch64: add new insn definition for st2g
Indu Bhagat
indu.bhagat@oracle.com
Fri May 2 20:32:04 GMT 2025
On 4/15/25 9:21 AM, Richard Sandiford wrote:
> Indu Bhagat <indu.bhagat@oracle.com> writes:
>> Store Allocation Tags (st2g) is an Armv8.5-A memory tagging (MTE)
>> instruction. It stores an allocation tag to two tag granules of memory.
>>
>> TBD:
>> - Not too sure what is the best way to generate the st2g yet; A
>> subsequent patch will emit them in one of the target hooks.
>
> Regarding the previous thread about this:
>
> https://gcc.gnu.org/pipermail/gcc-patches/2024-November/668671.html
>
> and your question about whether all types of store tag instructions
> should be volatile: if we went for that approach, then yeah, I think so.
>
> As I mentioned there, I don't think we should use (unspec ...) memory
> addresses.
>
> But thinking more about it: can we guarantee that GCC will only use
> these instruction patterns with base registers that are aligned to
> 16 bytes? If so, then perhaps an alternative would be to model
> them as read-modify-write operations to the whole granule (even though
> the actual instructions leave normal memory untouched and only change
> the tags). That is, rather than:
>
>>
>> gcc/ChangeLog:
>>
>> * config/aarch64/aarch64.md (st2g): New definition.
>> ---
>> gcc/config/aarch64/aarch64.md | 20 ++++++++++++++++++++
>> 1 file changed, 20 insertions(+)
>>
>> diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
>> index 0c7aebb838cd..d3223e275c51 100644
>> --- a/gcc/config/aarch64/aarch64.md
>> +++ b/gcc/config/aarch64/aarch64.md
>> @@ -8475,6 +8475,26 @@
>> [(set_attr "type" "memtag")]
>> )
>>
>> +;; ST2G updates allocation tags for two memory granules (i.e. 32 bytes) at
>> +;; once, without zero initialization.
>> +(define_insn "st2g"
>> + [(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)))
>> + (set (mem:QI (unspec:DI
>> + [(plus:DI (match_dup 1)
>> + (match_operand:DI 3 "aarch64_granule16_simm9" "i"))]
>> + UNSPEC_TAG_SPACE))
>> + (and:QI (lshiftrt:DI (match_dup 0)
>> + (const_int 56)) (const_int 15)))]
>> + "TARGET_MEMTAG && (INTVAL (operands[2]) - 16 == INTVAL (operands[3]))"
>> + "st2g\\t%0, [%1, #%2]"
>> + [(set_attr "type" "memtag")]
>> +)
>> +
>
> ...this, we could do:
>
> (set (match_operand:OI 0 "aarch64_granule_memory_operand" "+<new constraint>")
> (unspec_volatile:OI
> [(match_dup 0)
> (match_operand:DI 1 "register_operand" "rk")]
> UNSPECV...))
>
> Using OImode (256 bytes) indicates that two full granules are affected
> by the store, but that no other memory is affected. The (match_dup 0)
> read indicates that this store does not kill any previous store to the
> same 256 bytes (since the contents of normal memory don't change).
> The unspec_volatile should ensure that nothing tries to remove the
> store as dead (which would especially be a problem when clearing tags).
>
I dont understand the statement: "The (match_dup 0) read indicates that
this store does not kill any previous store to the same 256 bytes".
I am currently seeing an issue (mentioned below).
> Using a single memory operand for the whole instruction has the advantage
> of only requiring one offset to be represented, rather than having both
> operands 2 and 3 in the original pattern. It also copes more easily
> with cases where the offset is zero for the first or second address,
> since no (plus ...) should be present in that case.
>
Currently I am using:
(define_insn "stg"
[(set (match_operand:TI 0 "aarch64_granule16_memory_operand" "+Umg")
(unspec_volatile:TI
[(match_dup 0)
(match_operand:DI 1 "register_operand" "rk")]
UNSPECV_TAG_SPACE))]
"TARGET_MEMTAG"
"stg\\t%1, %0"
[(set_attr "type" "memtag")]
)
...
(define_predicate "aarch64_granule16_memory_operand"
(and (match_test "TARGET_MEMTAG")
(and (match_code "mem")
(match_test "aarch64_granule16_memory_address_p (op)"))))
where aarch64_granule16_memory_address_p () simply checks for
aarch64_granule16_simm9 immediate for now.
Basically, I was expecting the generation of a POST_MODIFY for :
stg x0, [x2]
add x2, x2, 16
But in the rtl dump (XX.c.300r.auto_inc_dec):
(insn 31 44 32 3 (set (mem:TI (plus:DI (reg/f:DI 122 [ _10 ])
(const_int 0 [0])) [0 S16 A8])
(unspec_volatile:TI [
(mem:TI (plus:DI (reg/f:DI 122 [ _10 ])
(const_int 0 [0])) [0 S16 A8])
(reg:DI 120)
] UNSPECV_TAG_SPACE)) "alloca-1.c":8:12 1231 {stg}
(nil))
(insn 32 31 33 3 (set (reg/f:DI 122 [ _10 ])
(plus:DI (reg/f:DI 122 [ _10 ])
(const_int 16 [0x10]))) "alloca-1.c":8:12 121 {*adddi3_aarch64}
(nil))
starting bb 3
33: {cc:CC=cmp(r121:DI,0x10);r121:DI=r121:DI-0x10;}
32: r122:DI=r122:DI+0x10
31: [r122:DI+0]=unspec/v[[r122:DI+0],r120:DI] 17
mem count failure
mem count failure
Basically I think we need to handle the read of (match_dup 0)
differently, or use:
(define_insn "st2g"
[(set (match_operand:OI 0 "aarch64_granule16_memory_operand" "+Umg")
(unspec_volatile:OI
[(match_operand:DI 1 "register_operand" "rk")]
UNSPECV_TAG_SPACE))]
"TARGET_MEMTAG"
"st2g\\t%1, %0"
[(set_attr "type" "memtag")]
)
But, removing (match_dup 0) is in direct contradiction to what you wrote
above for (match_dup 0)...
More information about the Gcc-patches
mailing list