gcc/ChangeLog: * config/loongarch/loongarch.cc (loongarch_symbolic_constant_p): Remove the sym+addend form from the SYMBOL_PCREL64 type symbol. (loongarch_output_mi_thunk): Add code model extreme support. (loongarch_option_override_internal): Supports option combinations of -cmodel=extreme and -mexplicit-relocs=none. (loongarch_handle_model_attribute): Remove detection code. * config/loongarch/loongarch.md (movdi_pcrel64): New templated. (movdi_got_disp): Likewise. * config/loongarch/predicates.md (symbolic_got_operand): Determine whether the symbol type is SYMBOL_GOT_DISP. (symbolic_pcrel64_operand): Determine whether the symbol type is SYMBOL_PCREL64.
gcc/testsuite/ChangeLog: * gcc.target/loongarch/func-call-extreme-5.c: New test. * gcc.target/loongarch/func-call-extreme-6.c: New test. --- gcc/config/loongarch/loongarch.cc | 28 +++++------ gcc/config/loongarch/loongarch.md | 50 +++++++++++++++++++ gcc/config/loongarch/predicates.md | 14 ++++++ .../loongarch/func-call-extreme-5.c | 7 +++ .../loongarch/func-call-extreme-6.c | 7 +++ 5 files changed, 91 insertions(+), 15 deletions(-) create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-extreme-5.c create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-extreme-6.c diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index 28d64135c54..6a3321327ea 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -1944,10 +1944,10 @@ 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); + case SYMBOL_PCREL64: case SYMBOL_GOT_DISP: case SYMBOL_TLS: return false; @@ -7450,12 +7450,22 @@ loongarch_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, allowed, otherwise load the address into a register first. */ if (use_sibcall_p) { - insn = emit_call_insn (gen_sibcall_internal (fnaddr, const0_rtx)); + if (TARGET_CMODEL_EXTREME) + { + emit_insn (gen_movdi_pcrel64 (temp1, fnaddr, temp2)); + insn = emit_call_insn (gen_sibcall_internal (temp1, const0_rtx)); + } + else + insn = emit_call_insn (gen_sibcall_internal (fnaddr, const0_rtx)); SIBLING_CALL_P (insn) = 1; } else { - loongarch_emit_move (temp1, fnaddr); + if (TARGET_CMODEL_EXTREME) + emit_insn (gen_movdi_pcrel64 (temp1, fnaddr, temp2)); + else + loongarch_emit_move (temp1, fnaddr); + emit_jump_insn (gen_indirect_jump (temp1)); } @@ -7583,10 +7593,6 @@ loongarch_option_override_internal (struct gcc_options *opts, switch (la_target.cmodel) { case CMODEL_EXTREME: - if (la_opt_explicit_relocs == EXPLICIT_RELOCS_NONE) - error ("code model %qs is not compatible with %s", - "extreme", "-mexplicit-relocs=none"); - if (opts->x_flag_plt) { if (global_options_set.x_flag_plt) @@ -7951,14 +7957,6 @@ loongarch_handle_model_attribute (tree *node, tree name, tree arg, int, *no_add_attrs = true; return NULL_TREE; } - if (la_opt_explicit_relocs == EXPLICIT_RELOCS_NONE) - { - error_at (DECL_SOURCE_LOCATION (decl), - "%qE attribute is not compatible with %s", name, - "-mexplicit-relocs=none"); - *no_add_attrs = true; - return NULL_TREE; - } arg = TREE_VALUE (arg); if (TREE_CODE (arg) != STRING_CST) diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md index d1f5b94f5d6..c0365dc9e99 100644 --- a/gcc/config/loongarch/loongarch.md +++ b/gcc/config/loongarch/loongarch.md @@ -85,6 +85,9 @@ (define_c_enum "unspec" [ UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1 UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1 + + UNSPEC_MOV_PCREL64 + UNSPEC_MOV_GOT_DISP ]) (define_c_enum "unspecv" [ @@ -2057,6 +2060,25 @@ (define_expand "movdi" { if (loongarch_legitimize_move (DImode, operands[0], operands[1])) DONE; + + enum loongarch_symbol_type symbol_type; + if (loongarch_symbolic_constant_p (operands[1], &symbol_type)) + { + if (symbol_type == SYMBOL_PCREL64) + { + gcc_assert (can_create_pseudo_p ()); + emit_insn (gen_movdi_pcrel64 (operands[0], operands[1], + gen_reg_rtx (DImode))); + DONE; + } + else if (TARGET_CMODEL_EXTREME && symbol_type == SYMBOL_GOT_DISP) + { + gcc_assert (can_create_pseudo_p ()); + emit_insn (gen_movdi_got_disp (operands[0], operands[1], + gen_reg_rtx (DImode))); + DONE; + } + } }) (define_insn_and_split "*movdi_32bit" @@ -2097,6 +2119,34 @@ (define_insn_and_split "*movdi_64bit" [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore") (set_attr "mode" "DI")]) +;; Use two registers to get the local symbol address. +;; la.local rd, rt, sym + +(define_insn "movdi_pcrel64" + [(set (match_operand:DI 0 "register_operand" "=r") + (match_operand:DI 1 "symbolic_pcrel64_operand")) + (unspec:DI [(const_int 0)] + UNSPEC_MOV_PCREL64) + (clobber (match_operand:DI 2 "register_operand" "=&r"))] + "TARGET_64BIT" + "la.local\t%0,%2,%1" + [(set_attr "mode" "DI") + (set_attr "length" "5")]) + +;; Use two registers to get the global symbol address from the got table. +;; la.global rd, rt, sym + +(define_insn "movdi_got_disp" + [(set (match_operand:DI 0 "register_operand" "=r") + (match_operand:DI 1 "symbolic_got_operand")) + (unspec:DI [(const_int 0)] + UNSPEC_MOV_GOT_DISP) + (clobber (match_operand:DI 2 "register_operand" "=&r"))] + "TARGET_64BIT && TARGET_CMODEL_EXTREME" + "la.global\t%0,%2,%1" + [(set_attr "mode" "DI") + (set_attr "length" "5")]) + ;; 32-bit Integer moves (define_expand "movsi" diff --git a/gcc/config/loongarch/predicates.md b/gcc/config/loongarch/predicates.md index ba5336cfb3e..d136dcc1c03 100644 --- a/gcc/config/loongarch/predicates.md +++ b/gcc/config/loongarch/predicates.md @@ -592,6 +592,20 @@ (define_predicate "mem_simple_ldst_operand" || symbolic_pcrel_offset_operand (op, Pmode)); }) +(define_predicate "symbolic_got_operand" + (match_code "const,symbol_ref,label_ref") +{ + enum loongarch_symbol_type type; + return loongarch_symbolic_constant_p (op, &type) && type == SYMBOL_GOT_DISP; +}) + +(define_predicate "symbolic_pcrel64_operand" + (match_code "const,symbol_ref,label_ref") +{ + enum loongarch_symbol_type type; + return loongarch_symbolic_constant_p (op, &type) && type == SYMBOL_PCREL64; +}) + (define_predicate "equality_operator" (match_code "eq,ne")) diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-5.c b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-5.c new file mode 100644 index 00000000000..8ecf5bc7525 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-5.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-mabi=lp64d -O0 -fpic -fno-plt -mexplicit-relocs=none -mcmodel=extreme" } */ +/* { dg-final { scan-assembler "test:.*la.global.*,\\\$r15,g" } } */ +/* { dg-final { scan-assembler "test1:.*la.global.*,\\\$r15,f" } } */ +/* { dg-final { scan-assembler "test2:.*la.local.*,\\\$r15,l" } } */ + +#include "func-call-extreme-1.c" diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-6.c b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-6.c new file mode 100644 index 00000000000..81830d4d215 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-6.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-mabi=lp64d -O0 -fno-pic -fno-plt -mexplicit-relocs=none -mcmodel=extreme" } */ +/* { dg-final { scan-assembler "test:.*la.global.*,\\\$r15,g" } } */ +/* { dg-final { scan-assembler "test1:.*la.local.*,\\\$r15,f" } } */ +/* { dg-final { scan-assembler "test2:.*la.local.*,\\\$r15,l" } } */ + +#include "func-call-extreme-1.c" -- 2.39.3