[v1] LoongArch: Added code generation support for call36 function calls.
Checks
Commit Message
When compiling with '-mcmodel=medium', the function call is made through
'pcaddu18i+jirl' if binutils supports call36, otherwise the
native implementation 'pcalau12i+jirl' is used.
gcc/ChangeLog:
* config.in: Regenerate.
* config/loongarch/loongarch-opts.h (HAVE_AS_SUPPORT_CALL36): Define macro.
* config/loongarch/loongarch.cc (loongarch_legitimize_call_address):
If binutils supports call36, the function call is not split over expand.
(loongarch_option_override_internal): If use call36, then turn off fipa-ra.
* config/loongarch/loongarch.md: Add call36 generation code.
* config/loongarch/predicates.md: Likewise.
* configure: Regenerate.
* configure.ac: Check whether binutils supports call36.
---
gcc/config.in | 6 ++
gcc/config/loongarch/loongarch-opts.h | 4 +
gcc/config/loongarch/loongarch.cc | 20 +++-
gcc/config/loongarch/loongarch.md | 138 +++++++++++++++++++++-----
gcc/config/loongarch/predicates.md | 7 +-
gcc/configure | 32 ++++++
gcc/configure.ac | 6 ++
7 files changed, 182 insertions(+), 31 deletions(-)
Comments
On Tue, 2023-11-14 at 17:45 +0800, Lulu Cheng wrote:
> + /* When function calls are made through call36, t0 register will be
> + implicitly modified, so '-fno-ipa-ra' needs to be set here. */
> case CMODEL_MEDIUM:
> + if (HAVE_AS_SUPPORT_CALL36)
> + opts->x_flag_ipa_ra = 0;
> + break;
Maybe we can add a (clobber (reg:P 12)) to the related insns instead?
在 2023/11/14 下午5:55, Xi Ruoyao 写道:
> On Tue, 2023-11-14 at 17:45 +0800, Lulu Cheng wrote:
>> + /* When function calls are made through call36, t0 register will be
>> + implicitly modified, so '-fno-ipa-ra' needs to be set here. */
>> case CMODEL_MEDIUM:
>> + if (HAVE_AS_SUPPORT_CALL36)
>> + opts->x_flag_ipa_ra = 0;
>> + break;
> Maybe we can add a (clobber (reg:P 12)) to the related insns instead?
>
Sorry, this was modified in accordance with the call36 macro instruction
during the test.
I will use clobber, and add test cases.
On Tue, 2023-11-14 at 20:46 +0800, chenglulu wrote:
>
> 在 2023/11/14 下午5:55, Xi Ruoyao 写道:
> > On Tue, 2023-11-14 at 17:45 +0800, Lulu Cheng wrote:
> > > + /* When function calls are made through call36, t0 register
> > > will be
> > > + implicitly modified, so '-fno-ipa-ra' needs to be set
> > > here. */
> > > case CMODEL_MEDIUM:
> > > + if (HAVE_AS_SUPPORT_CALL36)
> > > + opts->x_flag_ipa_ra = 0;
> > > + break;
> > Maybe we can add a (clobber (reg:P 12)) to the related insns
> > instead?
> >
> Sorry, this was modified in accordance with the call36 macro
> instruction
> during the test.
> I will use clobber, and add test cases.
There seems a better solution as suggested by the GCC internal doc.
Section 18.9.16 mentions -fipa-ra:
-- Target Hook: bool TARGET_CALL_FUSAGE_CONTAINS_NON_CALLEE_CLOBBERS
Set to true if each call that binds to a local definition
explicitly clobbers or sets all non-fixed registers modified by
performing the call. That is, by the call pattern itself, or by
code that might be inserted by the linker (e.g. stubs, veneers,
branch islands), but not including those modifiable by the callee.
The affected registers may be mentioned explicitly in the call
pattern, or included as clobbers in CALL_INSN_FUNCTION_USAGE. The
default version of this hook is set to false. The purpose of this
hook is to enable the fipa-ra optimization.
So we can add t0 into CALL_INSN_FUNCTION_USAGE of the call insn, like:
diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md
index ea36542b1c3..96e7e98e6b3 100644
--- a/gcc/config/loongarch/loongarch.md
+++ b/gcc/config/loongarch/loongarch.md
@@ -3274,7 +3274,14 @@ (define_expand "sibcall"
XEXP (target, 1),
operands[1]));
else
- emit_call_insn (gen_sibcall_internal (target, operands[1]));
+ {
+ rtx call = gen_sibcall_internal (target, operands[1]);
+
+ if (TARGET_CMODEL_MEDIUM && !REG_P (target))
+ clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
+ gen_rtx_REG (Pmode, T0_REGNUM));
+ emit_call_insn (call);
+ }
DONE;
})
Likewise for sibcall_value.
By the way we'd better have a command line switch to override the build-
time check for assembler call36 support, because it makes writing test
cases and inter-operating with different versions of assembler easier.
On Wed, 2023-11-15 at 04:26 +0800, Xi Ruoyao wrote:
> On Tue, 2023-11-14 at 20:46 +0800, chenglulu wrote:
> >
> > 在 2023/11/14 下午5:55, Xi Ruoyao 写道:
> > > On Tue, 2023-11-14 at 17:45 +0800, Lulu Cheng wrote:
> > > > + /* When function calls are made through call36, t0 register
> > > > will be
> > > > + implicitly modified, so '-fno-ipa-ra' needs to be set
> > > > here. */
> > > > case CMODEL_MEDIUM:
> > > > + if (HAVE_AS_SUPPORT_CALL36)
> > > > + opts->x_flag_ipa_ra = 0;
> > > > + break;
> > > Maybe we can add a (clobber (reg:P 12)) to the related insns
> > > instead?
> > >
> > Sorry, this was modified in accordance with the call36 macro
> > instruction
> > during the test.
> > I will use clobber, and add test cases.
>
> There seems a better solution as suggested by the GCC internal doc.
> Section 18.9.16 mentions -fipa-ra:
>
> -- Target Hook: bool TARGET_CALL_FUSAGE_CONTAINS_NON_CALLEE_CLOBBERS
> Set to true if each call that binds to a local definition
> explicitly clobbers or sets all non-fixed registers modified by
> performing the call. That is, by the call pattern itself, or by
> code that might be inserted by the linker (e.g. stubs, veneers,
> branch islands), but not including those modifiable by the callee.
> The affected registers may be mentioned explicitly in the call
> pattern, or included as clobbers in CALL_INSN_FUNCTION_USAGE. The
> default version of this hook is set to false. The purpose of this
> hook is to enable the fipa-ra optimization.
>
> So we can add t0 into CALL_INSN_FUNCTION_USAGE of the call insn, like:
>
> diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md
> index ea36542b1c3..96e7e98e6b3 100644
> --- a/gcc/config/loongarch/loongarch.md
> +++ b/gcc/config/loongarch/loongarch.md
> @@ -3274,7 +3274,14 @@ (define_expand "sibcall"
> XEXP (target, 1),
> operands[1]));
> else
> - emit_call_insn (gen_sibcall_internal (target, operands[1]));
> + {
> + rtx call = gen_sibcall_internal (target, operands[1]);
> +
> + if (TARGET_CMODEL_MEDIUM && !REG_P (target))
> + clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
> + gen_rtx_REG (Pmode, T0_REGNUM));
> + emit_call_insn (call);
> + }
> DONE;
> })
>
> Likewise for sibcall_value.
Nope. This does not work for
__attribute__((noinline)) void q() { asm ("":::"memory"); }
__attribute__((noinline)) static void t() { q(); }
int
main ()
{
int x0 = 114514;
asm("":"+r"(x0));
t();
if (x0 != 114514)
__builtin_trap ();
}
Not sure why...
>
> By the way we'd better have a command line switch to override the build-
> time check for assembler call36 support, because it makes writing test
> cases and inter-operating with different versions of assembler easier.
>
On Wed, 2023-11-15 at 04:42 +0800, Xi Ruoyao wrote:
> > There seems a better solution as suggested by the GCC internal doc.
> > Section 18.9.16 mentions -fipa-ra:
> >
> > -- Target Hook: bool TARGET_CALL_FUSAGE_CONTAINS_NON_CALLEE_CLOBBERS
> > Set to true if each call that binds to a local definition
> > explicitly clobbers or sets all non-fixed registers modified by
> > performing the call. That is, by the call pattern itself, or by
> > code that might be inserted by the linker (e.g. stubs, veneers,
> > branch islands), but not including those modifiable by the callee.
> > The affected registers may be mentioned explicitly in the call
> > pattern, or included as clobbers in CALL_INSN_FUNCTION_USAGE. The
> > default version of this hook is set to false. The purpose of this
> > hook is to enable the fipa-ra optimization.
> >
> > So we can add t0 into CALL_INSN_FUNCTION_USAGE of the call insn, like:
> >
> > diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md
> > index ea36542b1c3..96e7e98e6b3 100644
> > --- a/gcc/config/loongarch/loongarch.md
> > +++ b/gcc/config/loongarch/loongarch.md
> > @@ -3274,7 +3274,14 @@ (define_expand "sibcall"
> > XEXP (target, 1),
> > operands[1]));
> > else
> > - emit_call_insn (gen_sibcall_internal (target, operands[1]));
> > + {
> > + rtx call = gen_sibcall_internal (target, operands[1]);
> > +
> > + if (TARGET_CMODEL_MEDIUM && !REG_P (target))
> > + clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
> > + gen_rtx_REG (Pmode, T0_REGNUM));
> > + emit_call_insn (call);
> > + }
> > DONE;
> > })
> >
> > Likewise for sibcall_value.
>
> Nope. This does not work for
>
> __attribute__((noinline)) void q() { asm ("":::"memory"); }
> __attribute__((noinline)) static void t() { q(); }
>
> int
> main ()
> {
> int x0 = 114514;
>
> asm("":"+r"(x0));
> t();
> if (x0 != 114514)
> __builtin_trap ();
> }
>
> Not sure why...
Alright, it should be
diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md
index ea36542b1c3..75c595abad7 100644
--- a/gcc/config/loongarch/loongarch.md
+++ b/gcc/config/loongarch/loongarch.md
@@ -3274,7 +3274,13 @@ (define_expand "sibcall"
XEXP (target, 1),
operands[1]));
else
- emit_call_insn (gen_sibcall_internal (target, operands[1]));
+ {
+ rtx call = emit_call_insn (gen_sibcall_internal (target, operands[1]));
+
+ if (TARGET_CMODEL_MEDIUM && !REG_P (target))
+ clobber_reg (&CALL_INSN_FUNCTION_USAGE (call),
+ gen_rtx_REG (Pmode, T0_REGNUM));
+ }
DONE;
})
instead.
@@ -775,6 +775,12 @@
#endif
+/* Define if your assembler supports call36. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_AS_SUPPORT_CALL36
+#endif
+
+
/* Define if your assembler and linker support thread-local storage. */
#ifndef USED_FOR_TARGET
#undef HAVE_AS_TLS
@@ -97,6 +97,10 @@ loongarch_update_gcc_opt_status (struct loongarch_target *target,
#define HAVE_AS_EXPLICIT_RELOCS 0
#endif
+#ifndef HAVE_AS_SUPPORT_CALL36
+#define HAVE_AS_SUPPORT_CALL36 0
+#endif
+
#ifndef HAVE_AS_MRELAX_OPTION
#define HAVE_AS_MRELAX_OPTION 0
#endif
@@ -3006,12 +3006,16 @@ loongarch_legitimize_call_address (rtx addr)
enum loongarch_symbol_type symbol_type = loongarch_classify_symbol (addr);
- /* Split function call insn 'bl sym' or 'bl %plt(sym)' to :
- pcalau12i $rd, %pc_hi20(sym)
- jr $rd, %pc_lo12(sym). */
+ /* If add the compilation option '-cmodel=medium', and the assembler does
+ not support call36. The following sequence of instructions will be
+ used for the function call:
+ pcalau12i $rd, %pc_hi20(sym)
+ jr $rd, %pc_lo12(sym)
+ */
if (TARGET_CMODEL_MEDIUM
- && TARGET_EXPLICIT_RELOCS
+ && !HAVE_AS_SUPPORT_CALL36
+ && (la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE)
&& (SYMBOL_REF_P (addr) || LABEL_REF_P (addr))
&& (symbol_type == SYMBOL_PCREL
|| (symbol_type == SYMBOL_GOT_DISP && flag_plt)))
@@ -7478,8 +7482,14 @@ loongarch_option_override_internal (struct gcc_options *opts,
}
break;
- case CMODEL_TINY_STATIC:
+ /* When function calls are made through call36, t0 register will be
+ implicitly modified, so '-fno-ipa-ra' needs to be set here. */
case CMODEL_MEDIUM:
+ if (HAVE_AS_SUPPORT_CALL36)
+ opts->x_flag_ipa_ra = 0;
+ break;
+
+ case CMODEL_TINY_STATIC:
case CMODEL_NORMAL:
case CMODEL_TINY:
case CMODEL_LARGE:
@@ -3274,10 +3274,25 @@ (define_insn "sibcall_internal"
[(call (mem:SI (match_operand 0 "call_insn_operand" "j,c,b"))
(match_operand 1 "" ""))]
"SIBLING_CALL_P (insn)"
- "@
- jr\t%0
- b\t%0
- b\t%%plt(%0)"
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return "jr\t%0";
+ case 1:
+ if (TARGET_CMODEL_MEDIUM)
+ return "pcaddu18i\t$r12,%%call36(%0)\n\tjirl\t$r0,$r12,0";
+ else
+ return "b\t%0";
+ case 2:
+ if (TARGET_CMODEL_MEDIUM)
+ return "pcaddu18i\t$r12,%%call36(%0)\n\tjirl\t$r0,$r12,0";
+ else
+ return "b\t%%plt(%0)";
+ default:
+ gcc_unreachable ();
+ }
+}
[(set_attr "jirl" "indirect,direct,direct")])
(define_insn "@sibcall_internal_1<mode>"
@@ -3337,10 +3352,25 @@ (define_insn "sibcall_value_internal"
(call (mem:SI (match_operand 1 "call_insn_operand" "j,c,b"))
(match_operand 2 "" "")))]
"SIBLING_CALL_P (insn)"
- "@
- jr\t%1
- b\t%1
- b\t%%plt(%1)"
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return "jr\t%1";
+ case 1:
+ if (TARGET_CMODEL_MEDIUM)
+ return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
+ else
+ return "b\t%1";
+ case 2:
+ if (TARGET_CMODEL_MEDIUM)
+ return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
+ else
+ return "b\t%%plt(%1)";
+ default:
+ gcc_unreachable ();
+ }
+}
[(set_attr "jirl" "indirect,direct,direct")])
(define_insn "@sibcall_value_internal_1<mode>"
@@ -3360,10 +3390,25 @@ (define_insn "sibcall_value_multiple_internal"
(call (mem:SI (match_dup 1))
(match_dup 2)))]
"SIBLING_CALL_P (insn)"
- "@
- jr\t%1
- b\t%1
- b\t%%plt(%1)"
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return "jr\t%1";
+ case 1:
+ if (TARGET_CMODEL_MEDIUM)
+ return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
+ else
+ return "b\t%1";
+ case 2:
+ if (TARGET_CMODEL_MEDIUM)
+ return "pcaddu18i\t$r12,%%call36(%1)\n\tjirl\t$r0,$r12,0";
+ else
+ return "b\t%%plt(%1)";
+ default:
+ gcc_unreachable ();
+ }
+}
[(set_attr "jirl" "indirect,direct,direct")])
(define_insn "@sibcall_value_multiple_internal_1<mode>"
@@ -3403,10 +3448,25 @@ (define_insn "call_internal"
(match_operand 1 "" ""))
(clobber (reg:SI RETURN_ADDR_REGNUM))]
""
- "@
- jirl\t$r1,%0,0
- bl\t%0
- bl\t%%plt(%0)"
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return "jirl\t$r1,%0,0";
+ case 1:
+ if (TARGET_CMODEL_MEDIUM)
+ return "pcaddu18i\t$r1,%%call36(%0)\n\tjirl\t$r1,$r1,0";
+ else
+ return "bl\t%0";
+ case 2:
+ if (TARGET_CMODEL_MEDIUM)
+ return "pcaddu18i\t$r1,%%call36(%0)\n\tjirl\t$r1,$r1,0";
+ else
+ return "bl\t%%plt(%0)";
+ default:
+ gcc_unreachable ();
+ }
+}
[(set_attr "jirl" "indirect,direct,direct")])
(define_insn "@call_internal_1<mode>"
@@ -3465,10 +3525,25 @@ (define_insn "call_value_internal"
(match_operand 2 "" "")))
(clobber (reg:SI RETURN_ADDR_REGNUM))]
""
- "@
- jirl\t$r1,%1,0
- bl\t%1
- bl\t%%plt(%1)"
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return "jirl\t$r1,%1,0";
+ case 1:
+ if (TARGET_CMODEL_MEDIUM)
+ return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
+ else
+ return "bl\t%1";
+ case 2:
+ if (TARGET_CMODEL_MEDIUM)
+ return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
+ else
+ return "bl\t%%plt(%1)";
+ default:
+ gcc_unreachable ();
+ }
+}
[(set_attr "jirl" "indirect,direct,direct")])
(define_insn "@call_value_internal_1<mode>"
@@ -3490,10 +3565,25 @@ (define_insn "call_value_multiple_internal"
(match_dup 2)))
(clobber (reg:SI RETURN_ADDR_REGNUM))]
""
- "@
- jirl\t$r1,%1,0
- bl\t%1
- bl\t%%plt(%1)"
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return "jirl\t$r1,%1,0";
+ case 1:
+ if (TARGET_CMODEL_MEDIUM)
+ return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
+ else
+ return "bl\t%1";
+ case 2:
+ if (TARGET_CMODEL_MEDIUM)
+ return "pcaddu18i\t$r1,%%call36(%1)\n\tjirl\t$r1,$r1,0";
+ else
+ return "bl\t%%plt(%1)";
+ default:
+ gcc_unreachable ();
+ }
+}
[(set_attr "jirl" "indirect,direct,direct")])
(define_insn "@call_value_multiple_internal_1<mode>"
@@ -443,7 +443,9 @@ (define_predicate "const_call_insn_operand"
{
case SYMBOL_PCREL:
if (TARGET_CMODEL_EXTREME
- || (TARGET_CMODEL_MEDIUM && !TARGET_EXPLICIT_RELOCS))
+ || (TARGET_CMODEL_MEDIUM
+ && HAVE_AS_SUPPORT_CALL36
+ && (la_opt_explicit_relocs == EXPLICIT_RELOCS_NONE)))
return false;
else
return 1;
@@ -452,7 +454,8 @@ (define_predicate "const_call_insn_operand"
if (TARGET_CMODEL_EXTREME
|| !flag_plt
|| (flag_plt && TARGET_CMODEL_MEDIUM
- && !TARGET_EXPLICIT_RELOCS))
+ && HAVE_AS_SUPPORT_CALL36
+ && (la_opt_explicit_relocs == EXPLICIT_RELOCS_NONE)))
return false;
else
return 1;
@@ -29349,6 +29349,38 @@ if test $gcc_cv_as_loongarch_explicit_relocs = yes; then
$as_echo "#define HAVE_AS_EXPLICIT_RELOCS 1" >>confdefs.h
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for call36 support" >&5
+$as_echo_n "checking assembler for call36 support... " >&6; }
+if ${gcc_cv_as_loongarch_call36+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ gcc_cv_as_loongarch_call36=no
+ if test x$gcc_cv_as != x; then
+ $as_echo 'pcaddu18i $r1, %call36(a)
+ jirl $r1, $r1, 0' > conftest.s
+ if { ac_try='$gcc_cv_as $gcc_cv_as_flags -o conftest.o conftest.s >&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }
+ then
+ gcc_cv_as_loongarch_call36=yes
+ else
+ echo "configure: failed program was" >&5
+ cat conftest.s >&5
+ fi
+ rm -f conftest.o conftest.s
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_loongarch_call36" >&5
+$as_echo "$gcc_cv_as_loongarch_call36" >&6; }
+if test $gcc_cv_as_loongarch_call36 = yes; then
+
+$as_echo "#define HAVE_AS_SUPPORT_CALL36 1" >>confdefs.h
+
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for eh_frame pcrel encoding support" >&5
@@ -5441,6 +5441,12 @@ x:
[a:pcalau12i $t0,%pc_hi20(a)],,
[AC_DEFINE(HAVE_AS_EXPLICIT_RELOCS, 1,
[Define if your assembler supports explicit relocation.])])
+ gcc_GAS_CHECK_FEATURE([call36 support],
+ gcc_cv_as_loongarch_call36,,
+ [pcaddu18i $r1, %call36(a)
+ jirl $r1, $r1, 0],,
+ [AC_DEFINE(HAVE_AS_SUPPORT_CALL36, 1,
+ [Define if your assembler supports call36.])])
gcc_GAS_CHECK_FEATURE([eh_frame pcrel encoding support],
gcc_cv_as_loongarch_eh_frame_pcrel_encoding_support,,
[.cfi_startproc