diff options
author | Xi Ruoyao <xry111@xry111.site> | 2023-10-01 11:14:29 +0800 |
---|---|---|
committer | Xi Ruoyao <xry111@xry111.site> | 2023-10-23 15:30:19 +0800 |
commit | 83e24e8c1e5eb3366e35d5b8494a4cd9a2395b59 (patch) | |
tree | 6b73e1ce098ba5ca2d38656d00dfa9c1e89c2cbb /gcc | |
parent | 95db62f4ad4cfce30b7683a7e3e9f06330e84878 (diff) | |
download | gcc-83e24e8c1e5eb3366e35d5b8494a4cd9a2395b59.zip gcc-83e24e8c1e5eb3366e35d5b8494a4cd9a2395b59.tar.gz gcc-83e24e8c1e5eb3366e35d5b8494a4cd9a2395b59.tar.bz2 |
LoongArch: Use explicit relocs for addresses only used for one load or store with -mexplicit-relocs=auto and -mcmodel={normal,medium}
In these cases, if we use explicit relocs, we end up with 2
instructions:
pcalau12i t0, %pc_hi20(x)
ld.d t0, t0, %pc_lo12(x)
If we use la.local pseudo-op, in the best scenario (x is in +/- 2MiB
range) we still have 2 instructions:
pcaddi t0, %pcrel_20(x)
ld.d t0, t0, 0
If x is out of the range we'll have 3 instructions. So for these cases
just emit machine instructions with explicit relocs.
gcc/ChangeLog:
* config/loongarch/predicates.md (symbolic_pcrel_operand): New
predicate.
* config/loongarch/loongarch.md (define_peephole2): Optimize
la.local + ld/st to pcalau12i + ld/st if the address is only used
once if -mexplicit-relocs=auto and -mcmodel=normal or medium.
gcc/testsuite/ChangeLog:
* gcc.target/loongarch/explicit-relocs-auto-single-load-store.c:
New test.
* gcc.target/loongarch/explicit-relocs-auto-single-load-store-no-anchor.c:
New test.
Diffstat (limited to 'gcc')
4 files changed, 149 insertions, 0 deletions
diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md index 695c8eb..1347347 100644 --- a/gcc/config/loongarch/loongarch.md +++ b/gcc/config/loongarch/loongarch.md @@ -65,6 +65,7 @@ UNSPEC_LOAD_FROM_GOT UNSPEC_PCALAU12I + UNSPEC_PCALAU12I_GR UNSPEC_ORI_L_LO12 UNSPEC_LUI_L_HI20 UNSPEC_LUI_H_LO20 @@ -2297,6 +2298,16 @@ "pcalau12i\t%0,%%pc_hi20(%1)" [(set_attr "type" "move")]) +;; @pcalau12i may be used for sibcall so it has a strict constraint. This +;; allows any general register as the operand. +(define_insn "@pcalau12i_gr<mode>" + [(set (match_operand:P 0 "register_operand" "=r") + (unspec:P [(match_operand:P 1 "symbolic_operand" "")] + UNSPEC_PCALAU12I_GR))] + "" + "pcalau12i\t%0,%%pc_hi20(%1)" + [(set_attr "type" "move")]) + (define_insn "@ori_l_lo12<mode>" [(set (match_operand:P 0 "register_operand" "=r") (unspec:P [(match_operand:P 1 "register_operand" "r") @@ -3748,6 +3759,117 @@ [(set_attr "type" "unknown") (set_attr "mode" "<MODE>")]) +;; With normal or medium code models, if the only use of a pc-relative +;; address is for loading or storing a value, then relying on linker +;; relaxation is not better than emitting the machine instruction directly. +;; Even if the la.local pseudo op can be relaxed, we get: +;; +;; pcaddi $t0, %pcrel_20(x) +;; ld.d $t0, $t0, 0 +;; +;; There are still two instructions, same as using the machine instructions +;; and explicit relocs: +;; +;; pcalau12i $t0, %pc_hi20(x) +;; ld.d $t0, $t0, %pc_lo12(x) +;; +;; And if the pseudo op cannot be relaxed, we'll get a worse result (with +;; 3 instructions). +(define_peephole2 + [(set (match_operand:P 0 "register_operand") + (match_operand:P 1 "symbolic_pcrel_operand")) + (set (match_operand:GPR 2 "register_operand") + (mem:GPR (match_dup 0)))] + "la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO \ + && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM) \ + && (peep2_reg_dead_p (2, operands[0]) \ + || REGNO (operands[0]) == REGNO (operands[2]))" + [(set (match_dup 2) (mem:GPR (lo_sum:P (match_dup 0) (match_dup 1))))] + { + emit_insn (gen_pcalau12i_gr<P:mode> (operands[0], operands[1])); + }) + +(define_peephole2 + [(set (match_operand:P 0 "register_operand") + (match_operand:P 1 "symbolic_pcrel_operand")) + (set (match_operand:GPR 2 "register_operand") + (mem:GPR (plus (match_dup 0) + (match_operand 3 "const_int_operand"))))] + "la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO \ + && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM) \ + && (peep2_reg_dead_p (2, operands[0]) \ + || REGNO (operands[0]) == REGNO (operands[2]))" + [(set (match_dup 2) (mem:GPR (lo_sum:P (match_dup 0) (match_dup 1))))] + { + operands[1] = plus_constant (Pmode, operands[1], INTVAL (operands[3])); + emit_insn (gen_pcalau12i_gr<P:mode> (operands[0], operands[1])); + }) + +(define_peephole2 + [(set (match_operand:P 0 "register_operand") + (match_operand:P 1 "symbolic_pcrel_operand")) + (set (match_operand:GPR 2 "register_operand") + (any_extend:GPR (mem:SUBDI (match_dup 0))))] + "la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO \ + && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM) \ + && (peep2_reg_dead_p (2, operands[0]) \ + || REGNO (operands[0]) == REGNO (operands[2]))" + [(set (match_dup 2) + (any_extend:GPR (mem:SUBDI (lo_sum:P (match_dup 0) + (match_dup 1)))))] + { + emit_insn (gen_pcalau12i_gr<P:mode> (operands[0], operands[1])); + }) + +(define_peephole2 + [(set (match_operand:P 0 "register_operand") + (match_operand:P 1 "symbolic_pcrel_operand")) + (set (match_operand:GPR 2 "register_operand") + (any_extend:GPR + (mem:SUBDI (plus (match_dup 0) + (match_operand 3 "const_int_operand")))))] + "la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO \ + && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM) \ + && (peep2_reg_dead_p (2, operands[0]) \ + || REGNO (operands[0]) == REGNO (operands[2]))" + [(set (match_dup 2) + (any_extend:GPR (mem:SUBDI (lo_sum:P (match_dup 0) + (match_dup 1)))))] + { + operands[1] = plus_constant (Pmode, operands[1], INTVAL (operands[3])); + emit_insn (gen_pcalau12i_gr<P:mode> (operands[0], operands[1])); + }) + +(define_peephole2 + [(set (match_operand:P 0 "register_operand") + (match_operand:P 1 "symbolic_pcrel_operand")) + (set (mem:QHWD (match_dup 0)) + (match_operand:QHWD 2 "register_operand"))] + "la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO \ + && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM) \ + && (peep2_reg_dead_p (2, operands[0])) \ + && REGNO (operands[0]) != REGNO (operands[2])" + [(set (mem:QHWD (lo_sum:P (match_dup 0) (match_dup 1))) (match_dup 2))] + { + emit_insn (gen_pcalau12i_gr<P:mode> (operands[0], operands[1])); + }) + +(define_peephole2 + [(set (match_operand:P 0 "register_operand") + (match_operand:P 1 "symbolic_pcrel_operand")) + (set (mem:QHWD (plus (match_dup 0) + (match_operand 3 "const_int_operand"))) + (match_operand:QHWD 2 "register_operand"))] + "la_opt_explicit_relocs == EXPLICIT_RELOCS_AUTO \ + && (TARGET_CMODEL_NORMAL || TARGET_CMODEL_MEDIUM) \ + && (peep2_reg_dead_p (2, operands[0])) \ + && REGNO (operands[0]) != REGNO (operands[2])" + [(set (mem:QHWD (lo_sum:P (match_dup 0) (match_dup 1))) (match_dup 2))] + { + operands[1] = plus_constant (Pmode, operands[1], INTVAL (operands[3])); + emit_insn (gen_pcalau12i_gr<P:mode> (operands[0], operands[1])); + }) + ;; Synchronization instructions. (include "sync.md") diff --git a/gcc/config/loongarch/predicates.md b/gcc/config/loongarch/predicates.md index 359878f..946ed0d 100644 --- a/gcc/config/loongarch/predicates.md +++ b/gcc/config/loongarch/predicates.md @@ -563,6 +563,13 @@ return loongarch_symbolic_constant_p (op, &type); }) +(define_predicate "symbolic_pcrel_operand" + (match_code "const,symbol_ref,label_ref") +{ + enum loongarch_symbol_type type; + return loongarch_symbolic_constant_p (op, &type) && type == SYMBOL_PCREL; +}) + (define_predicate "equality_operator" (match_code "eq,ne")) diff --git a/gcc/testsuite/gcc.target/loongarch/explicit-relocs-auto-single-load-store-no-anchor.c b/gcc/testsuite/gcc.target/loongarch/explicit-relocs-auto-single-load-store-no-anchor.c new file mode 100644 index 0000000..fb03403 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/explicit-relocs-auto-single-load-store-no-anchor.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=loongarch64 -mabi=lp64d -mexplicit-relocs=auto -fno-section-anchors" } */ + +#include "explicit-relocs-auto-single-load-store.c" + +/* { dg-final { scan-assembler-not "la.local" } } */ diff --git a/gcc/testsuite/gcc.target/loongarch/explicit-relocs-auto-single-load-store.c b/gcc/testsuite/gcc.target/loongarch/explicit-relocs-auto-single-load-store.c new file mode 100644 index 0000000..0d53644 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/explicit-relocs-auto-single-load-store.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=loongarch64 -mabi=lp64d -mexplicit-relocs=auto" } */ + +long a; +int b; +unsigned int c; + +long load_a() { return a; } +long load_b() { return b; } +long load_c() { return c; } +void store_a(long x) { a = x; } +void store_b(int x) { b = x; } + +/* { dg-final { scan-assembler-not "la.local" } } */ |