public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/vendors/ARM/heads/morello)] Make move_block_to_reg safe for MEMs with a size that isn't a multiple of word_mode
@ 2022-02-28 12:07 Matthew Malcomson
  0 siblings, 0 replies; only message in thread
From: Matthew Malcomson @ 2022-02-28 12:07 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:3fb5b3645dd5d39d634b5bb7236349315f21b8cd

commit 3fb5b3645dd5d39d634b5bb7236349315f21b8cd
Author: Stam Markianos-Wright <stam.markianos-wright@arm.com>
Date:   Fri Dec 10 16:36:23 2021 +0000

    Make move_block_to_reg safe for MEMs with a size that isn't a multiple of word_mode
    
    move_block_to_reg would emit a loop of word_mode (DImode) loads
    to move BLK data from memory into registers. This could result
    in overreading if the data contained an un-aligned packed struct
    or a complex number (_Complex char with a `.size 2`
    is what is used in the tests)
    
    Fix this by removing one iteration from the loop and creating a
    tail that is smaller than word_mode. Then load this tail using
    extract_bit_field, which will take care not to exceed the bounds
    of the struct.
    
    This function does not risk invalidating any capabilities, because
    it is never reached with any struct or union containing capabilities.
    
    The function currently has 2 call sites:
    
    - `emit_push_insn`: the function gets called if `partial > 0` and
     `GET_CODE (reg) != PARALLEL` which can never happen with AArch64.
    
    - `load_register_parameters`: the function gets called if the
       parameter to a C function call is going to be passed in a register
       _and_ is already in BLKmode _and_ the `reg` destination has not
       been given `GET_CODE (reg) == PARALLEL`. I have not been able to
       trigger this from C code:
       - A struct containing only a capability is not in BLKmode,
         it gets to the caller in CADImode, so gets moved with a `emit_move_insn`
         instead
       - A union of a capability with another data type similarly had a mode when
         arriving at the caller, so also was moved with a `emit_move_insn`.
       - A struct containing a capability with another data that was small enough
         to be passed in registers has a `PARALLEL` reg destination, so it get
         moved done with `emit_group_move`.

Diff:
---
 gcc/expr.c | 30 ++++++++++++++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)

diff --git a/gcc/expr.c b/gcc/expr.c
index a04b77f6309..cffc02f692f 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -2129,10 +2129,36 @@ move_block_to_reg (int regno, rtx x, int nregs, machine_mode mode)
       else
 	delete_insns_since (last);
     }
-
-  for (int i = 0; i < nregs; i++)
+  /* First run all but the final iteration in word_mode.  */
+  for (int i = 0; i < nregs - 1; i++)
     emit_move_insn (gen_rtx_REG (word_mode, regno + i),
 		    operand_subword_force (x, i, mode));
+
+  /* Run the final iteration: For capability argets we need to take care here
+     to not over-read from memory. If the total size to move is greater than
+     the MEM_SIZE, then we have a tail that is smaller than word_mode, so
+     get the remainder and use extract_bit_field to load the tail into the reg.
+     Fot non-capability targets perform a standard move as in the loop
+     above.  */
+  int remainder;
+  poly_int64 q;
+  if (MEM_P (x) && CAPABILITY_MODE_P (GET_MODE (XEXP (x, 0)))
+      && MEM_SIZE_KNOWN_P (x)
+      && maybe_gt (nregs * GET_MODE_SIZE (word_mode), MEM_SIZE (x))
+      && can_div_trunc_p (MEM_SIZE (x), GET_MODE_SIZE (word_mode),
+			  &q, &remainder))
+   {
+      rtx return_reg = gen_rtx_REG (word_mode, regno + nregs - 1);
+      emit_move_insn (return_reg,
+		      extract_bit_field (x, remainder * BITS_PER_UNIT, 0, 0,
+					 0, remainder * BITS_PER_UNIT - 1,
+					 return_reg, word_mode, word_mode, 0,
+					 NULL));
+      return;
+   }
+   else
+    emit_move_insn (gen_rtx_REG (word_mode, regno + nregs - 1),
+		    operand_subword_force (x, nregs - 1, mode));
 }
 
 /* Copy all or part of a BLKmode value X out of registers starting at REGNO.


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-02-28 12:07 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-28 12:07 [gcc(refs/vendors/ARM/heads/morello)] Make move_block_to_reg safe for MEMs with a size that isn't a multiple of word_mode Matthew Malcomson

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).