From c426a3caef5502a07db08d8f6e5678511bf9da63 Mon Sep 17 00:00:00 2001
From: Iain Sandoe <iain@sandoe.co.uk>
Date: Sat, 20 Feb 2021 12:14:08 +0000
Subject: [PATCH] aarch64, Darwin : Restrict offsets for prfm.

The current LLVM-based assemblers reject offsets that are not suitable
for prfm as written in the local section.  However, there is advice
elsewhere that says that this category of instruction should attempt
to use the 9bit unscaled version before falling back to the scaled one.

In the short-term reject values that the assembler will not accept.

This partially addresses Issue #43

gcc/

	* config/aarch64/aarch64.c (aarch64_address_valid_for_prefetch_p):
	Reject values incompatible with pfrum and out of range for pfrm.
	For Mach-O, reject values that require prfum.

(cherry picked from commit 76e872ee44318cafbd24b58e23234889164b67fd)
Signed-off-by: Kirill A. Korinsky <kirill@korins.ky>
---
 gcc/config/aarch64/aarch64.c | 28 +++++++++++++++++++++++++---
 1 file changed, 25 insertions(+), 3 deletions(-)

diff --git gcc/config/aarch64/aarch64.c gcc/config/aarch64/aarch64.c
index c51aa0cd0fd..58fb5675a46 100644
--- gcc/config/aarch64/aarch64.c
+++ gcc/config/aarch64/aarch64.c
@@ -9739,9 +9739,31 @@ aarch64_address_valid_for_prefetch_p (rtx x, bool strict_p)
   if (!res)
     return false;
 
-  /* Darwinpcs allows addresses on the stack that are not DImode aligned.  */
-  if (TARGET_MACHO && addr.offset && (INTVAL (addr.offset) & 0x07))
-    return false;
+  /* For ELF targets using GAS, we emit prfm unconditionally; GAS will alter
+     the instruction to pick the prfum form where possible (i.e. when the
+     offset is in the range -256..255) and fall back to prfm otherwise.
+     We can reject cases where the offset exceeds the range usable by both
+     insns [-256..32760], or for offsets > 255 when the value is not divisible
+     by 8.
+     For Mach-O (Darwin) where the assembler uses the LLVM back end, that does
+     not yet do the substitution, so we must reject all prfum cases.  */
+  if (addr.offset)
+    {
+      HOST_WIDE_INT offs = INTVAL (addr.offset);
+      if (offs < -256) /* Out of range for both prfum and prfm.  */
+	return false;
+      if (offs > 32760) /* Out of range for prfm.  */
+	return false;
+      if (offs & 0x07)
+	{
+	  if (offs > 255) /* Out of range for prfum.  */
+	    return false;
+	  if (TARGET_MACHO)
+	    return false;
+	}
+      if (TARGET_MACHO && offs < 0)
+	return false;
+    }
 
   /* ... except writeback forms.  */
   return addr.type != ADDRESS_REG_WB;
-- 
2.42.1

