在 2022/8/24 下午10:12, Xi Ruoyao 写道: > On Wed, 2022-08-24 at 22:08 +0800, Xi Ruoyao wrote: >> v1 -> v2: >> >>  * Avoid introduce of SYMBOL_PCREL32, use SYMBOL_PCREL for 32-bit PC >>    relative. >>  * Rebase onto a bug fix ([1/2] in the series) to avoid merge conflict. >>  * Fix missed ChangeLog entries. > Resend because my mail client has done some stupid thing to the patch :( > > -- >8 -- > > A linker script and/or a section attribute may locate some object > specially, so we need to handle the code model for such objects > differently than the -mcmodel setting. This happens when the Linux > kernel loads a module with per-CPU variables. > > Add an attribute to override the code model for a specific variable. > > gcc/ChangeLog: > > * config/loongarch/loongarch-protos.h (loongarch_symbol_type): > Add SYMBOL_PCREL64 and change the description for SYMBOL_PCREL. > * config/loongarch/loongarch.cc (loongarch_attribute_table): > New attribute table. > (TARGET_ATTRIBUTE_TABLE): Define the target hook. > (loongarch_handle_model_attribute): New static function. > (loongarch_classify_symbol): Take TARGET_CMODEL_EXTREME and the > model attribute of SYMBOL_REF_DECL into account returning > SYMBOL_PCREL or SYMBOL_PCREL64. > (loongarch_use_anchors_for_symbol_p): New static function. > (TARGET_USE_ANCHORS_FOR_SYMBOL_P): Define the target hook. > (loongarch_symbol_extreme_p): New static function. > (loongarch_symbolic_constant_p): Handle SYMBOL_PCREL64. > (loongarch_symbol_insns): Likewise. > (loongarch_split_symbol_type): Likewise. > (loongarch_split_symbol): Check SYMBOL_PCREL64 instead of > TARGET_CMODEL_EXTREME for PC-relative addressing. > (loongarch_print_operand_reloc): Likewise. > * doc/extend.texi (Variable Attributes): Document new > LoongArch specific attribute. > > gcc/testsuite/ChangeLog: > > * gcc.target/loongarch/attr-model-test.c: New test. > * gcc.target/loongarch/attr-model-1.c: New test. > * gcc.target/loongarch/attr-model-2.c: New test. > * gcc.target/loongarch/attr-model-diag.c: New test. > --- > gcc/config/loongarch/loongarch-protos.h | 8 +- > gcc/config/loongarch/loongarch.cc | 190 ++++++++++++++++-- > gcc/doc/extend.texi | 16 ++ > .../gcc.target/loongarch/attr-model-1.c | 6 + > .../gcc.target/loongarch/attr-model-2.c | 6 + > .../gcc.target/loongarch/attr-model-diag.c | 7 + > .../gcc.target/loongarch/attr-model-test.c | 25 +++ > 7 files changed, 237 insertions(+), 21 deletions(-) > create mode 100644 gcc/testsuite/gcc.target/loongarch/attr-model-1.c > create mode 100644 gcc/testsuite/gcc.target/loongarch/attr-model-2.c > create mode 100644 gcc/testsuite/gcc.target/loongarch/attr-model-diag.c > create mode 100644 gcc/testsuite/gcc.target/loongarch/attr-model-test.c > > diff --git a/gcc/config/loongarch/loongarch-protos.h b/gcc/config/loongarch/loongarch-protos.h > index cadaad7519c..77b2217247d 100644 > --- a/gcc/config/loongarch/loongarch-protos.h > +++ b/gcc/config/loongarch/loongarch-protos.h > @@ -28,7 +28,12 @@ along with GCC; see the file COPYING3. If not see > The symbol's value will be loaded directly from the GOT. > > SYMBOL_PCREL > - The symbol's value will be loaded directly from data section. > + The symbol's value will be loaded directly from data section within > + +/- 2GiB range. > + > + SYMBOL_PCREL64 > + The symbol's value will be loaded directly from data section within > + +/- 8EiB range. > > SYMBOL_TLS > A thread-local symbol. > @@ -42,6 +47,7 @@ along with GCC; see the file COPYING3. If not see > enum loongarch_symbol_type { > SYMBOL_GOT_DISP, > SYMBOL_PCREL, > + SYMBOL_PCREL64, > SYMBOL_TLS, > SYMBOL_TLS_IE, > SYMBOL_TLS_LE, > diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc > index 41d9cca6d31..d9061cdeee3 100644 > --- a/gcc/config/loongarch/loongarch.cc > +++ b/gcc/config/loongarch/loongarch.cc > @@ -1633,8 +1633,11 @@ loongarch_rtx_constant_in_small_data_p (machine_mode mode) > static enum loongarch_symbol_type > loongarch_classify_symbol (const_rtx x) > { > + enum loongarch_symbol_type pcrel = > + TARGET_CMODEL_EXTREME ? SYMBOL_PCREL64 : SYMBOL_PCREL; > + > if (!SYMBOL_REF_P (x)) > - return SYMBOL_PCREL; > + return pcrel; > > if (SYMBOL_REF_TLS_MODEL (x)) > return SYMBOL_TLS; > @@ -1642,7 +1645,28 @@ loongarch_classify_symbol (const_rtx x) > if (!loongarch_symbol_binds_local_p (x)) > return SYMBOL_GOT_DISP; > > - return SYMBOL_PCREL; > + tree t = SYMBOL_REF_DECL (x); > + if (!t) > + return pcrel; > + > + t = lookup_attribute ("model", DECL_ATTRIBUTES (t)); > + if (!t) > + return pcrel; > + > + t = TREE_VALUE (TREE_VALUE (t)); > + > + /* loongarch_handle_model_attribute should reject other values. */ > + gcc_assert (TREE_CODE (t) == STRING_CST); > + > + const char *model = TREE_STRING_POINTER (t); > + if (strcmp (model, "normal") == 0) > + return SYMBOL_PCREL; > + if (strcmp (model, "extreme") == 0) > + return SYMBOL_PCREL64; > + > + /* loongarch_handle_model_attribute should reject unknown model > + name. */ > + gcc_unreachable (); > } > > /* Classify the base of symbolic expression X, given that X appears in > @@ -1695,6 +1719,7 @@ loongarch_symbolic_constant_p (rtx x, enum loongarch_symbol_type *symbol_type) > case SYMBOL_TLSGD: > case SYMBOL_TLSLDM: > case SYMBOL_PCREL: > + case SYMBOL_PCREL64: > /* GAS rejects offsets outside the range [-2^31, 2^31-1]. */ > return sext_hwi (INTVAL (offset), 32) == INTVAL (offset); > > @@ -1729,6 +1754,9 @@ loongarch_symbol_insns (enum loongarch_symbol_type type, machine_mode mode) > case SYMBOL_TLSLDM: > return 3; > > + case SYMBOL_PCREL64: > + return 5; > + > case SYMBOL_TLS: > /* We don't treat a bare TLS symbol as a constant. */ > return 0; > @@ -1833,7 +1861,7 @@ loongarch_valid_offset_p (rtx x, machine_mode mode) > return true; > } > > -/* Should a symbol of type SYMBOL_TYPE should be split in two? */ > +/* Should a symbol of type SYMBOL_TYPE should be split in two or more? */ > > bool > loongarch_split_symbol_type (enum loongarch_symbol_type symbol_type) > @@ -1841,6 +1869,7 @@ loongarch_split_symbol_type (enum loongarch_symbol_type symbol_type) > switch (symbol_type) > { > case SYMBOL_PCREL: > + case SYMBOL_PCREL64: > case SYMBOL_GOT_DISP: > case SYMBOL_TLS_IE: > case SYMBOL_TLS_LE: > @@ -2718,6 +2747,20 @@ loongarch_force_address (rtx x, machine_mode mode) > return x; > } > > +static bool > +loongarch_symbol_extreme_p (enum loongarch_symbol_type type) > +{ > + switch (type) > + { > + case SYMBOL_PCREL: > + return false; > + case SYMBOL_PCREL64: > + return true; > + default: > + return TARGET_CMODEL_EXTREME; > + } > +} > + > /* If MODE is MAX_MACHINE_MODE, ADDR appears as a move operand, otherwise > it appears in a MEM of that mode. Return true if ADDR is a legitimate > constant in that context and can be split into high and low parts. > @@ -2757,7 +2800,7 @@ loongarch_split_symbol (rtx temp, rtx addr, machine_mode mode, rtx *low_out) > high = gen_rtx_HIGH (Pmode, copy_rtx (addr)); > high = loongarch_force_temporary (temp, high); > > - if (TARGET_CMODEL_EXTREME && can_create_pseudo_p ()) > + if (loongarch_symbol_extreme_p (symbol_type) && can_create_pseudo_p ()) > { > gcc_assert (TARGET_EXPLICIT_RELOCS); > > @@ -2771,14 +2814,16 @@ loongarch_split_symbol (rtx temp, rtx addr, machine_mode mode, rtx *low_out) > if (low_out) > switch (symbol_type) > { > - case SYMBOL_PCREL: > - { > - if (TARGET_CMODEL_EXTREME && can_create_pseudo_p ()) > + case SYMBOL_PCREL64: > + if (can_create_pseudo_p ()) > + { > *low_out = gen_rtx_PLUS (Pmode, high, temp1); > - else > - *low_out = gen_rtx_LO_SUM (Pmode, high, addr); > - break; > - } > + break; > + } > + /* fall through */ > + case SYMBOL_PCREL: > + *low_out = gen_rtx_LO_SUM (Pmode, high, addr); > + break; > > case SYMBOL_GOT_DISP: > /* SYMBOL_GOT_DISP symbols are loaded from the GOT. */ > @@ -4745,22 +4790,23 @@ loongarch_print_operand_reloc (FILE *file, rtx op, bool hi64_part, > bool hi_reloc) > { > const char *reloc; > + enum loongarch_symbol_type symbol_type = > + loongarch_classify_symbolic_expression (op); > > - if (TARGET_CMODEL_EXTREME) > + if (loongarch_symbol_extreme_p (symbol_type)) > gcc_assert (TARGET_EXPLICIT_RELOCS); > > - switch (loongarch_classify_symbolic_expression (op)) > + switch (symbol_type) > { > - case SYMBOL_PCREL: > + case SYMBOL_PCREL64: > if (hi64_part) > { > - if (TARGET_CMODEL_EXTREME) > - reloc = hi_reloc ? "%pc64_hi12" : "%pc64_lo20"; > - else > - gcc_unreachable (); > + reloc = hi_reloc ? "%pc64_hi12" : "%pc64_lo20"; > + break; > } > - else > - reloc = hi_reloc ? "%pc_hi20" : "%pc_lo12"; > + /* fall through */ > + case SYMBOL_PCREL: > + reloc = hi_reloc ? "%pc_hi20" : "%pc_lo12"; > break; > > case SYMBOL_GOT_DISP: > @@ -6316,6 +6362,104 @@ loongarch_starting_frame_offset (void) > return crtl->outgoing_args_size; > } > > +static tree > +loongarch_handle_model_attribute (tree *node, tree name, tree arg, int, > + bool *no_add_attrs) > +{ > + tree decl = *node; > + if (TREE_CODE (decl) == VAR_DECL) > + { > + if (DECL_THREAD_LOCAL_P (decl)) > + { > + error_at (DECL_SOURCE_LOCATION (decl), > + "%qE attribute cannot be specified for thread-local " > + "variables", name); > + *no_add_attrs = true; > + return NULL_TREE; > + } > + if (DECL_CONTEXT (decl) > + && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL > + && !TREE_STATIC (decl)) > + { > + error_at (DECL_SOURCE_LOCATION (decl), > + "%qE attribute cannot be specified for local " > + "variables", name); > + *no_add_attrs = true; > + return NULL_TREE; > + } > + if (DECL_REGISTER (decl)) > + { > + error_at (DECL_SOURCE_LOCATION (decl), > + "%qE attribute cannot be specified for register " > + "variables", name); > + *no_add_attrs = true; > + return NULL_TREE; > + } > + if (!TARGET_EXPLICIT_RELOCS) > + { > + error_at (DECL_SOURCE_LOCATION (decl), > + "%qE attribute requires %s", name, "-mexplicit-relocs"); > + *no_add_attrs = true; > + return NULL_TREE; > + } > + > + arg = TREE_VALUE (arg); > + if (TREE_CODE (arg) != STRING_CST) > + { > + error_at (DECL_SOURCE_LOCATION (decl), > + "invalid argument of %qE attribute", name); > + *no_add_attrs = true; > + return NULL_TREE; > + } > + > + const char *model = TREE_STRING_POINTER (arg); > + if (strcmp (model, "normal") != 0 > + && strcmp (model, "extreme") != 0) > + { > + error_at (DECL_SOURCE_LOCATION (decl), > + "invalid argument of %qE attribute", name); > + *no_add_attrs = true; > + return NULL_TREE; > + } > + > + if (lookup_attribute ("model", DECL_ATTRIBUTES (decl))) > + { > + error_at (DECL_SOURCE_LOCATION (decl), > + "multiple %qE attribute", name); > + *no_add_attrs = true; > + return NULL_TREE; > + } > + } > + else > + { > + warning (OPT_Wattributes, "%qE attribute ignored", name); > + *no_add_attrs = true; > + } > + return NULL_TREE; > +} > + > +static const struct attribute_spec loongarch_attribute_table[] = > +{ > + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, > + affects_type_identity, handler, exclude } */ > + { "model", 1, 1, true, false, false, false, > + loongarch_handle_model_attribute, NULL }, > + /* The last attribute spec is set to be NULL. */ > + {} > +}; > + > +bool > +loongarch_use_anchors_for_symbol_p (const_rtx symbol) > +{ > + tree decl = SYMBOL_REF_DECL (symbol); > + > + /* The section anchor optimization may break custom address model. */ > + if (decl && lookup_attribute ("model", DECL_ATTRIBUTES (decl))) > + return false; > + > + return default_use_anchors_for_symbol_p (symbol); > +} > + > /* Initialize the GCC target structure. */ > #undef TARGET_ASM_ALIGNED_HI_OP > #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t" > @@ -6504,6 +6648,12 @@ loongarch_starting_frame_offset (void) > #undef TARGET_HAVE_SPECULATION_SAFE_VALUE > #define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed > > +#undef TARGET_ATTRIBUTE_TABLE > +#define TARGET_ATTRIBUTE_TABLE loongarch_attribute_table > + > +#undef TARGET_USE_ANCHORS_FOR_SYMBOL_P > +#define TARGET_USE_ANCHORS_FOR_SYMBOL_P loongarch_use_anchors_for_symbol_p > + > struct gcc_target targetm = TARGET_INITIALIZER; > > #include "gt-loongarch.h" > diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi > index 7fe7f8817cd..431811c7b26 100644 > --- a/gcc/doc/extend.texi > +++ b/gcc/doc/extend.texi > @@ -7314,6 +7314,7 @@ attributes. > * Blackfin Variable Attributes:: > * H8/300 Variable Attributes:: > * IA-64 Variable Attributes:: > +* LoongArch Variable Attributes:: > * M32R/D Variable Attributes:: > * MeP Variable Attributes:: > * Microsoft Windows Variable Attributes:: > @@ -8098,6 +8099,21 @@ defined by shared libraries. > > @end table > > +@node LoongArch Variable Attributes > +@subsection LoongArch Variable Attributes > + > +One attribute is currently defined for the LoongArch. > + > +@table @code > +@item model("@var{name}") > +@cindex @code{model} variable attribute, LoongArch > +Use this attribute on the LoongArch to use a different code model for > +addressing this variable, than the code model specified by the global > +@option{-mcmodel} option.This attribute is mostly useful if a > +@code{section} attribute and/or a linker script will locate this object > +specially. I think this should add a sentence: "Currently, the identifier name can only be one of small or extreme." Others I think are ok. > +@end table > + > @node M32R/D Variable Attributes > @subsection M32R/D Variable Attributes > > diff --git a/gcc/testsuite/gcc.target/loongarch/attr-model-1.c b/gcc/testsuite/gcc.target/loongarch/attr-model-1.c > new file mode 100644 > index 00000000000..916d715b98b > --- /dev/null > +++ b/gcc/testsuite/gcc.target/loongarch/attr-model-1.c > @@ -0,0 +1,6 @@ > +/* { dg-do compile } */ > +/* { dg-options "-mexplicit-relocs -mcmodel=normal -O2" } */ > +/* { dg-final { scan-assembler-times "%pc64_hi12" 2 } } */ > + > +#define ATTR_MODEL_TEST > +#include "attr-model-test.c" > diff --git a/gcc/testsuite/gcc.target/loongarch/attr-model-2.c b/gcc/testsuite/gcc.target/loongarch/attr-model-2.c > new file mode 100644 > index 00000000000..a74c795ac3e > --- /dev/null > +++ b/gcc/testsuite/gcc.target/loongarch/attr-model-2.c > @@ -0,0 +1,6 @@ > +/* { dg-do compile } */ > +/* { dg-options "-mexplicit-relocs -mcmodel=extreme -O2" } */ > +/* { dg-final { scan-assembler-times "%pc64_hi12" 3 } } */ > + > +#define ATTR_MODEL_TEST > +#include "attr-model-test.c" > diff --git a/gcc/testsuite/gcc.target/loongarch/attr-model-diag.c b/gcc/testsuite/gcc.target/loongarch/attr-model-diag.c > new file mode 100644 > index 00000000000..88beede74df > --- /dev/null > +++ b/gcc/testsuite/gcc.target/loongarch/attr-model-diag.c > @@ -0,0 +1,7 @@ > +/* { dg-do compile } */ > +/* { dg-options "-mexplicit-relocs" } */ > + > +__thread int x __attribute__((model("extreme"))); /* { dg-error "attribute cannot be specified for thread-local variables" } */ > +register int y __asm__("tp") __attribute__((model("extreme"))); /* { dg-error "attribute cannot be specified for register variables" } */ > +int z __attribute__((model(114))); /* { dg-error "invalid argument" } */ > +int t __attribute__((model("good"))); /* { dg-error "invalid argument" } */ > diff --git a/gcc/testsuite/gcc.target/loongarch/attr-model-test.c b/gcc/testsuite/gcc.target/loongarch/attr-model-test.c > new file mode 100644 > index 00000000000..5b61a7af9c3 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/loongarch/attr-model-test.c > @@ -0,0 +1,25 @@ > +#ifdef ATTR_MODEL_TEST > +int x __attribute__((model("extreme"))); > +int y __attribute__((model("normal"))); > +int z; > + > +int > +test(void) > +{ > + return x + y + z; > +} > + > +/* The following will be used for kernel per-cpu storage implemention. */ > + > +register char *per_cpu_base __asm__("r21"); > +static int counter __attribute__((section(".data..percpu"), model("extreme"))); > + > +void > +inc_counter(void) > +{ > + int *ptr = (int *)(per_cpu_base + (long)&counter); > + (*ptr)++; > +} > +#endif > + > +int dummy;