[WIP][PATCH] RISC-V: Add `-mgprel' option for GP-relative addressing

Maciej W. Rozycki macro@wdc.com
Mon Aug 31 14:09:18 GMT 2020


Implement `-mgprel', forcing `-mexplicit-relocs' whenever the option is 
active due to the lack of GAS macro support for GP-relative addressing.

	gcc/
	* riscv/riscv-protos.h (riscv_symbol_type): Add SYMBOL_GPREL 
	enumeration constant.
	* config/riscv/riscv.c (riscv_classify_symbol)
	(riscv_symbolic_constant_p, riscv_symbol_insns)
	(riscv_split_symbol_type, riscv_split_symbol, riscv_output_move)
	(riscv_print_operand_reloc, riscv_option_override): Handle 
	GP-relative addressing.
	* config/riscv/riscv.md (unspec): Add UNSPEC_GPREL enumeration 
	constant.
	* config/riscv/riscv.opt (mgprel): New option.
---
Hi,

 This is very early stage really, just implementing basic GP-relative
relocation support, in preparation for FDPIC support discussed here:

<https://groups.google.com/a/groups.riscv.org/g/sw-dev/c/ZjYUJswknQ4>

I planned adding support to GAS macros such as LA next so that we don't 
have to force explicit relocations with `-mgprel' for this option to work, 
but I won't be able to continue with this effort now as I am leaving 
Western Digital today, so I am posting this in case someone finds it 
useful or wishes to continue the effort.

 No regressions in `riscv64-linux-gnu' testing, RV32/ilp32d ABI with QEMU 
in the Linux user emulation mode across all GCC frontends and libraries, 
except for an odd ICE with one of the Fortran test cases and a couple 
timeouts with GNAT test cases, which I put all on the version difference 
between the test runs (10.0.1 20200426 vs 11.0.0 20200827).  

 Unfortunately I lost several hours, because 11.0.0 20200829 has regressed 
enough compared to 11.0.0 20200827 for testing not to progress well enough 
in 15 hours where it usually completes in ~10 hours.  So I had to restart 
with an older snapshot and wouldn't get reference results in time (I only 
had libgo results with 11.0.0 20200827).  I think my assumption as to the 
nature of the regressions is right though.

 A corresponding binutils change has also been posted.

  Maciej
---
 gcc/config/riscv/riscv-protos.h |    1 +
 gcc/config/riscv/riscv.c        |   32 +++++++++++++++++++++++++++++---
 gcc/config/riscv/riscv.md       |    1 +
 gcc/config/riscv/riscv.opt      |    4 ++++
 4 files changed, 35 insertions(+), 3 deletions(-)

gcc-riscv-gprel.diff
Index: gcc/gcc/config/riscv/riscv-protos.h
===================================================================
--- gcc.orig/gcc/config/riscv/riscv-protos.h
+++ gcc/gcc/config/riscv/riscv-protos.h
@@ -28,6 +28,7 @@ enum riscv_symbol_type {
   SYMBOL_ABSOLUTE,
   SYMBOL_PCREL,
   SYMBOL_GOT_DISP,
+  SYMBOL_GPREL,
   SYMBOL_TLS,
   SYMBOL_TLS_LE,
   SYMBOL_TLS_IE,
Index: gcc/gcc/config/riscv/riscv.c
===================================================================
--- gcc.orig/gcc/config/riscv/riscv.c
+++ gcc/gcc/config/riscv/riscv.c
@@ -559,7 +559,13 @@ riscv_classify_symbol (const_rtx x)
   if (GET_CODE (x) == SYMBOL_REF && flag_pic && !riscv_symbol_binds_local_p (x))
     return SYMBOL_GOT_DISP;
 
-  return riscv_cmodel == CM_MEDLOW ? SYMBOL_ABSOLUTE : SYMBOL_PCREL;
+  if (riscv_cmodel == CM_MEDLOW)
+    return SYMBOL_ABSOLUTE;
+
+  if (LABEL_REF_P (x) || (SYMBOL_REF_P (x) && SYMBOL_REF_FUNCTION_P (x)))
+    return SYMBOL_PCREL;
+
+  return TARGET_GPREL ? SYMBOL_GPREL : SYMBOL_PCREL;
 }
 
 /* Classify the base of symbolic expression X.  */
@@ -604,6 +610,7 @@ riscv_symbolic_constant_p (rtx x, enum r
     case SYMBOL_ABSOLUTE:
     case SYMBOL_PCREL:
     case SYMBOL_TLS_LE:
+    case SYMBOL_GPREL:
       /* GAS rejects offsets outside the range [-2^31, 2^31-1].  */
       return sext_hwi (INTVAL (offset), 32) == INTVAL (offset);
 
@@ -622,6 +629,7 @@ static int riscv_symbol_insns (enum risc
     case SYMBOL_ABSOLUTE: return 2; /* LUI + the reference.  */
     case SYMBOL_PCREL: return 2; /* AUIPC + the reference.  */
     case SYMBOL_TLS_LE: return 3; /* LUI + ADD TP + the reference.  */
+    case SYMBOL_GPREL: return 3; /* LUI + ADD GP + the reference.  */
     case SYMBOL_GOT_DISP: return 3; /* AUIPC + LD GOT + the reference.  */
     default: gcc_unreachable ();
     }
@@ -735,7 +743,9 @@ riscv_split_symbol_type (enum riscv_symb
   if (!TARGET_EXPLICIT_RELOCS)
     return false;
 
-  return symbol_type == SYMBOL_ABSOLUTE || symbol_type == SYMBOL_PCREL;
+  return (symbol_type == SYMBOL_ABSOLUTE
+	  || symbol_type == SYMBOL_PCREL
+	  || symbol_type == SYMBOL_GPREL);
 }
 
 /* Return true if a LO_SUM can address a value of mode MODE when the
@@ -1241,6 +1251,17 @@ riscv_split_symbol (rtx temp, rtx addr,
 	}
 	break;
 
+      case SYMBOL_GPREL:
+	{
+	  rtx high = gen_rtx_HIGH (Pmode, copy_rtx (addr));
+	  rtx gp = gen_rtx_REG (Pmode, GP_REGNUM);
+	  high = riscv_force_temporary (temp, high, in_splitter);
+	  rtx reg = gen_rtx_PLUS (Pmode, high, gp);
+	  reg = riscv_force_temporary (temp, reg, in_splitter);
+	  *low_out = gen_rtx_LO_SUM (Pmode, reg, addr);
+	}
+	break;
+
       default:
 	gcc_unreachable ();
       }
@@ -2030,6 +2051,7 @@ riscv_output_move (rtx dest, rtx src)
 	  case SYMBOL_GOT_DISP: return "la\t%0,%1";
 	  case SYMBOL_ABSOLUTE: return "lla\t%0,%1";
 	  case SYMBOL_PCREL: return "lla\t%0,%1";
+	  case SYMBOL_GPREL: return "la\t%0,%1";
 	  default: gcc_unreachable ();
 	  }
     }
@@ -3290,6 +3312,10 @@ riscv_print_operand_reloc (FILE *file, r
 	reloc = hi_reloc ? "%tprel_hi" : "%tprel_lo";
 	break;
 
+      case SYMBOL_GPREL:
+	reloc = hi_reloc ? "%gprel_hi" : "%gprel_lo";
+	break;
+
       default:
 	output_operand_lossage ("invalid use of '%%%c'", hi_reloc ? 'h' : 'R');
 	return;
@@ -4735,7 +4761,7 @@ riscv_option_override (void)
   /* We get better code with explicit relocs for CM_MEDLOW, but
      worse code for the others (for now).  Pick the best default.  */
   if ((target_flags_explicit & MASK_EXPLICIT_RELOCS) == 0)
-    if (riscv_cmodel == CM_MEDLOW)
+    if (riscv_cmodel == CM_MEDLOW || TARGET_GPREL)
       target_flags |= MASK_EXPLICIT_RELOCS;
 
   /* Require that the ISA supports the requested floating-point ABI.  */
Index: gcc/gcc/config/riscv/riscv.md
===================================================================
--- gcc.orig/gcc/config/riscv/riscv.md
+++ gcc/gcc/config/riscv/riscv.md
@@ -28,6 +28,7 @@
   UNSPEC_ADDRESS_FIRST
   UNSPEC_PCREL
   UNSPEC_LOAD_GOT
+  UNSPEC_GPREL
   UNSPEC_TLS
   UNSPEC_TLS_LE
   UNSPEC_TLS_IE
Index: gcc/gcc/config/riscv/riscv.opt
===================================================================
--- gcc.orig/gcc/config/riscv/riscv.opt
+++ gcc/gcc/config/riscv/riscv.opt
@@ -179,3 +179,7 @@ Use the given offset for addressing the
 
 TargetVariable
 long riscv_stack_protector_guard_offset = 0
+
+mgprel
+Target Report Mask(GPREL)
+Use GP-relative sequences for data accesses.


More information about the Gcc-patches mailing list