1239 lines
40 KiB
Diff
1239 lines
40 KiB
Diff
|
|
From 078261cabef370e7f3201980d03bd54a049290e9 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Lulu Cheng <chenglulu@loongson.cn>
|
||
|
|
Date: Thu, 21 Jul 2022 11:04:08 +0800
|
||
|
|
Subject: [PATCH 004/124] LoongArch: Support split symbol.
|
||
|
|
|
||
|
|
Add compilation option '-mexplicit-relocs', and if enable '-mexplicit-relocs'
|
||
|
|
the symbolic address load instruction 'la.*' will be split into two instructions.
|
||
|
|
This compilation option enabled by default.
|
||
|
|
|
||
|
|
gcc/ChangeLog:
|
||
|
|
|
||
|
|
* common/config/loongarch/loongarch-common.cc:
|
||
|
|
Enable '-fsection-anchors' when O1 and more advanced optimization.
|
||
|
|
* config/loongarch/genopts/loongarch.opt.in: Add new option
|
||
|
|
'-mexplicit-relocs', and enable by default.
|
||
|
|
* config/loongarch/loongarch-protos.h (loongarch_split_move_insn_p):
|
||
|
|
Delete function declaration.
|
||
|
|
(loongarch_split_move_insn): Delete function declaration.
|
||
|
|
(loongarch_split_symbol_type): Add function declaration.
|
||
|
|
* config/loongarch/loongarch.cc (enum loongarch_address_type):
|
||
|
|
Add new address type 'ADDRESS_LO_SUM'.
|
||
|
|
(loongarch_classify_symbolic_expression): New function definitions.
|
||
|
|
Classify the base of symbolic expression X, given that X appears in
|
||
|
|
context CONTEXT.
|
||
|
|
(loongarch_symbol_insns): Add a judgment condition TARGET_EXPLICIT_RELOCS.
|
||
|
|
(loongarch_split_symbol_type): New function definitions.
|
||
|
|
Determines whether the symbol load should be split into two instructions.
|
||
|
|
(loongarch_valid_lo_sum_p): New function definitions.
|
||
|
|
Return true if a LO_SUM can address a value of mode MODE when the LO_SUM
|
||
|
|
symbol has type SYMBOL_TYPE.
|
||
|
|
(loongarch_classify_address): Add handling of 'LO_SUM'.
|
||
|
|
(loongarch_address_insns): Add handling of 'ADDRESS_LO_SUM'.
|
||
|
|
(loongarch_signed_immediate_p): Sort code.
|
||
|
|
(loongarch_12bit_offset_address_p): Return true if address type is ADDRESS_LO_SUM.
|
||
|
|
(loongarch_const_insns): Add handling of 'HIGH'.
|
||
|
|
(loongarch_split_move_insn_p): Add the static attribute to the function.
|
||
|
|
(loongarch_emit_set): New function definitions.
|
||
|
|
(loongarch_call_tls_get_addr): Add symbol handling when defining TARGET_EXPLICIT_RELOCS.
|
||
|
|
(loongarch_legitimize_tls_address): Add symbol handling when defining the
|
||
|
|
TARGET_EXPLICIT_RELOCS macro.
|
||
|
|
(loongarch_split_symbol): New function definitions. Split symbol.
|
||
|
|
(loongarch_legitimize_address): Add codes see if the address can split into a high part
|
||
|
|
and a LO_SUM.
|
||
|
|
(loongarch_legitimize_const_move): Add codes split moves of symbolic constants into
|
||
|
|
high and low.
|
||
|
|
(loongarch_split_move_insn): Delete function definitions.
|
||
|
|
(loongarch_output_move): Add support for HIGH and LO_SUM.
|
||
|
|
(loongarch_print_operand_reloc): New function definitions.
|
||
|
|
Print symbolic operand OP, which is part of a HIGH or LO_SUM in context CONTEXT.
|
||
|
|
(loongarch_memmodel_needs_release_fence): Sort code.
|
||
|
|
(loongarch_print_operand): Rearrange alphabetical order and add H and L to support HIGH
|
||
|
|
and LOW output.
|
||
|
|
(loongarch_print_operand_address): Add handling of 'ADDRESS_LO_SUM'.
|
||
|
|
(TARGET_MIN_ANCHOR_OFFSET): Define macro to -IMM_REACH/2.
|
||
|
|
(TARGET_MAX_ANCHOR_OFFSET): Define macro to IMM_REACH/2-1.
|
||
|
|
* config/loongarch/loongarch.md (movti): Delete the template.
|
||
|
|
(*movti): Delete the template.
|
||
|
|
(movtf): Delete the template.
|
||
|
|
(*movtf): Delete the template.
|
||
|
|
(*low<mode>): New template of normal symbol low address.
|
||
|
|
(@tls_low<mode>): New template of tls symbol low address.
|
||
|
|
(@ld_from_got<mode>): New template load address from got table.
|
||
|
|
(@ori_l_lo12<mode>): New template.
|
||
|
|
* config/loongarch/loongarch.opt: Update from loongarch.opt.in.
|
||
|
|
* config/loongarch/predicates.md: Add support for symbol_type HIGH.
|
||
|
|
|
||
|
|
gcc/testsuite/ChangeLog:
|
||
|
|
|
||
|
|
* gcc.target/loongarch/func-call-1.c: Add build option '-mno-explicit-relocs'.
|
||
|
|
* gcc.target/loongarch/func-call-2.c: Add build option '-mno-explicit-relocs'.
|
||
|
|
* gcc.target/loongarch/func-call-3.c: Add build option '-mno-explicit-relocs'.
|
||
|
|
* gcc.target/loongarch/func-call-4.c: Add build option '-mno-explicit-relocs'.
|
||
|
|
* gcc.target/loongarch/func-call-5.c: New test.
|
||
|
|
* gcc.target/loongarch/func-call-6.c: New test.
|
||
|
|
* gcc.target/loongarch/func-call-7.c: New test.
|
||
|
|
* gcc.target/loongarch/func-call-8.c: New test.
|
||
|
|
* gcc.target/loongarch/relocs-symbol-noaddend.c: New test.
|
||
|
|
|
||
|
|
Signed-off-by: Peng Fan <fanpeng@loongson.cn>
|
||
|
|
Signed-off-by: ticat_fp <fanpeng@loongson.cn>
|
||
|
|
---
|
||
|
|
.../config/loongarch/loongarch-common.cc | 1 +
|
||
|
|
gcc/config/loongarch/genopts/loongarch.opt.in | 4 +
|
||
|
|
gcc/config/loongarch/loongarch-protos.h | 3 +-
|
||
|
|
gcc/config/loongarch/loongarch.cc | 412 ++++++++++++++++--
|
||
|
|
gcc/config/loongarch/loongarch.md | 122 +++---
|
||
|
|
gcc/config/loongarch/loongarch.opt | 4 +
|
||
|
|
gcc/config/loongarch/predicates.md | 20 +-
|
||
|
|
.../gcc.target/loongarch/func-call-1.c | 2 +-
|
||
|
|
.../gcc.target/loongarch/func-call-2.c | 2 +-
|
||
|
|
.../gcc.target/loongarch/func-call-3.c | 2 +-
|
||
|
|
.../gcc.target/loongarch/func-call-4.c | 2 +-
|
||
|
|
.../gcc.target/loongarch/func-call-5.c | 33 ++
|
||
|
|
.../gcc.target/loongarch/func-call-6.c | 33 ++
|
||
|
|
.../gcc.target/loongarch/func-call-7.c | 34 ++
|
||
|
|
.../gcc.target/loongarch/func-call-8.c | 33 ++
|
||
|
|
.../loongarch/relocs-symbol-noaddend.c | 23 +
|
||
|
|
16 files changed, 614 insertions(+), 116 deletions(-)
|
||
|
|
create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-5.c
|
||
|
|
create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-6.c
|
||
|
|
create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-7.c
|
||
|
|
create mode 100644 gcc/testsuite/gcc.target/loongarch/func-call-8.c
|
||
|
|
create mode 100644 gcc/testsuite/gcc.target/loongarch/relocs-symbol-noaddend.c
|
||
|
|
|
||
|
|
diff --git a/gcc/common/config/loongarch/loongarch-common.cc b/gcc/common/config/loongarch/loongarch-common.cc
|
||
|
|
index ed3730fce..f8b4660fa 100644
|
||
|
|
--- a/gcc/common/config/loongarch/loongarch-common.cc
|
||
|
|
+++ b/gcc/common/config/loongarch/loongarch-common.cc
|
||
|
|
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3. If not see
|
||
|
|
static const struct default_options loongarch_option_optimization_table[] =
|
||
|
|
{
|
||
|
|
{ OPT_LEVELS_ALL, OPT_fasynchronous_unwind_tables, NULL, 1 },
|
||
|
|
+ { OPT_LEVELS_1_PLUS, OPT_fsection_anchors, NULL, 1 },
|
||
|
|
{ OPT_LEVELS_NONE, 0, NULL, 0 }
|
||
|
|
};
|
||
|
|
|
||
|
|
diff --git a/gcc/config/loongarch/genopts/loongarch.opt.in b/gcc/config/loongarch/genopts/loongarch.opt.in
|
||
|
|
index 61e7d72a0..6f3950093 100644
|
||
|
|
--- a/gcc/config/loongarch/genopts/loongarch.opt.in
|
||
|
|
+++ b/gcc/config/loongarch/genopts/loongarch.opt.in
|
||
|
|
@@ -154,6 +154,10 @@ mmax-inline-memcpy-size=
|
||
|
|
Target Joined RejectNegative UInteger Var(loongarch_max_inline_memcpy_size) Init(1024)
|
||
|
|
-mmax-inline-memcpy-size=SIZE Set the max size of memcpy to inline, default is 1024.
|
||
|
|
|
||
|
|
+mexplicit-relocs
|
||
|
|
+Target Var(TARGET_EXPLICIT_RELOCS) Init(1)
|
||
|
|
+Use %reloc() assembly operators.
|
||
|
|
+
|
||
|
|
; The code model option names for -mcmodel.
|
||
|
|
Enum
|
||
|
|
Name(cmodel) Type(int)
|
||
|
|
diff --git a/gcc/config/loongarch/loongarch-protos.h b/gcc/config/loongarch/loongarch-protos.h
|
||
|
|
index 080766250..cadaad751 100644
|
||
|
|
--- a/gcc/config/loongarch/loongarch-protos.h
|
||
|
|
+++ b/gcc/config/loongarch/loongarch-protos.h
|
||
|
|
@@ -77,8 +77,6 @@ extern rtx loongarch_legitimize_call_address (rtx);
|
||
|
|
extern rtx loongarch_subword (rtx, bool);
|
||
|
|
extern bool loongarch_split_move_p (rtx, rtx);
|
||
|
|
extern void loongarch_split_move (rtx, rtx, rtx);
|
||
|
|
-extern bool loongarch_split_move_insn_p (rtx, rtx);
|
||
|
|
-extern void loongarch_split_move_insn (rtx, rtx, rtx);
|
||
|
|
extern const char *loongarch_output_move (rtx, rtx);
|
||
|
|
extern bool loongarch_cfun_has_cprestore_slot_p (void);
|
||
|
|
#ifdef RTX_CODE
|
||
|
|
@@ -160,6 +158,7 @@ extern rtx loongarch_expand_thread_pointer (rtx);
|
||
|
|
extern bool loongarch_eh_uses (unsigned int);
|
||
|
|
extern bool loongarch_epilogue_uses (unsigned int);
|
||
|
|
extern bool loongarch_load_store_bonding_p (rtx *, machine_mode, bool);
|
||
|
|
+extern bool loongarch_split_symbol_type (enum loongarch_symbol_type);
|
||
|
|
|
||
|
|
typedef rtx (*mulsidi3_gen_fn) (rtx, rtx, rtx);
|
||
|
|
|
||
|
|
diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc
|
||
|
|
index 2e2f16e72..1b5af2c7d 100644
|
||
|
|
--- a/gcc/config/loongarch/loongarch.cc
|
||
|
|
+++ b/gcc/config/loongarch/loongarch.cc
|
||
|
|
@@ -100,6 +100,10 @@ along with GCC; see the file COPYING3. If not see
|
||
|
|
ADDRESS_REG_REG
|
||
|
|
A base register indexed by (optionally scaled) register.
|
||
|
|
|
||
|
|
+ ADDRESS_LO_SUM
|
||
|
|
+ A LO_SUM rtx. The first operand is a valid base register and the second
|
||
|
|
+ operand is a symbolic address.
|
||
|
|
+
|
||
|
|
ADDRESS_CONST_INT
|
||
|
|
A signed 16-bit constant address.
|
||
|
|
|
||
|
|
@@ -109,6 +113,7 @@ enum loongarch_address_type
|
||
|
|
{
|
||
|
|
ADDRESS_REG,
|
||
|
|
ADDRESS_REG_REG,
|
||
|
|
+ ADDRESS_LO_SUM,
|
||
|
|
ADDRESS_CONST_INT,
|
||
|
|
ADDRESS_SYMBOLIC
|
||
|
|
};
|
||
|
|
@@ -1641,6 +1646,21 @@ loongarch_classify_symbol (const_rtx x)
|
||
|
|
return SYMBOL_PCREL;
|
||
|
|
}
|
||
|
|
|
||
|
|
+/* Classify the base of symbolic expression X, given that X appears in
|
||
|
|
+ context CONTEXT. */
|
||
|
|
+
|
||
|
|
+static enum loongarch_symbol_type
|
||
|
|
+loongarch_classify_symbolic_expression (rtx x)
|
||
|
|
+{
|
||
|
|
+ rtx offset;
|
||
|
|
+
|
||
|
|
+ split_const (x, &x, &offset);
|
||
|
|
+ if (UNSPEC_ADDRESS_P (x))
|
||
|
|
+ return UNSPEC_ADDRESS_TYPE (x);
|
||
|
|
+
|
||
|
|
+ return loongarch_classify_symbol (x);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
/* Return true if X is a symbolic constant. If it is,
|
||
|
|
store the type of the symbol in *SYMBOL_TYPE. */
|
||
|
|
|
||
|
|
@@ -1696,7 +1716,7 @@ loongarch_symbol_insns (enum loongarch_symbol_type type, machine_mode mode)
|
||
|
|
case SYMBOL_GOT_DISP:
|
||
|
|
/* The constant will have to be loaded from the GOT before it
|
||
|
|
is used in an address. */
|
||
|
|
- if (mode != MAX_MACHINE_MODE)
|
||
|
|
+ if (!TARGET_EXPLICIT_RELOCS && mode != MAX_MACHINE_MODE)
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
return 3;
|
||
|
|
@@ -1814,6 +1834,84 @@ loongarch_valid_offset_p (rtx x, machine_mode mode)
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
+/* Should a symbol of type SYMBOL_TYPE should be split in two? */
|
||
|
|
+
|
||
|
|
+bool
|
||
|
|
+loongarch_split_symbol_type (enum loongarch_symbol_type symbol_type)
|
||
|
|
+{
|
||
|
|
+ switch (symbol_type)
|
||
|
|
+ {
|
||
|
|
+ case SYMBOL_PCREL:
|
||
|
|
+ case SYMBOL_GOT_DISP:
|
||
|
|
+ case SYMBOL_TLS_IE:
|
||
|
|
+ case SYMBOL_TLS_LE:
|
||
|
|
+ case SYMBOL_TLSGD:
|
||
|
|
+ case SYMBOL_TLSLDM:
|
||
|
|
+ return true;
|
||
|
|
+
|
||
|
|
+ case SYMBOL_TLS:
|
||
|
|
+ return false;
|
||
|
|
+
|
||
|
|
+ default:
|
||
|
|
+ gcc_unreachable ();
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/* Return true if a LO_SUM can address a value of mode MODE when the
|
||
|
|
+ LO_SUM symbol has type SYMBOL_TYPE. */
|
||
|
|
+
|
||
|
|
+static bool
|
||
|
|
+loongarch_valid_lo_sum_p (enum loongarch_symbol_type symbol_type,
|
||
|
|
+ machine_mode mode, rtx x)
|
||
|
|
+{
|
||
|
|
+ int align, size;
|
||
|
|
+
|
||
|
|
+ /* Check that symbols of type SYMBOL_TYPE can be used to access values
|
||
|
|
+ of mode MODE. */
|
||
|
|
+ if (loongarch_symbol_insns (symbol_type, mode) == 0)
|
||
|
|
+ return false;
|
||
|
|
+
|
||
|
|
+ /* Check that there is a known low-part relocation. */
|
||
|
|
+ if (!loongarch_split_symbol_type (symbol_type))
|
||
|
|
+ return false;
|
||
|
|
+
|
||
|
|
+ /* We can't tell size or alignment when we have BLKmode, so try extracing a
|
||
|
|
+ decl from the symbol if possible. */
|
||
|
|
+ if (mode == BLKmode)
|
||
|
|
+ {
|
||
|
|
+ rtx offset;
|
||
|
|
+
|
||
|
|
+ /* Extract the symbol from the LO_SUM operand, if any. */
|
||
|
|
+ split_const (x, &x, &offset);
|
||
|
|
+
|
||
|
|
+ /* Might be a CODE_LABEL. We can compute align but not size for that,
|
||
|
|
+ so don't bother trying to handle it. */
|
||
|
|
+ if (!SYMBOL_REF_P (x))
|
||
|
|
+ return false;
|
||
|
|
+
|
||
|
|
+ /* Use worst case assumptions if we don't have a SYMBOL_REF_DECL. */
|
||
|
|
+ align = (SYMBOL_REF_DECL (x)
|
||
|
|
+ ? DECL_ALIGN (SYMBOL_REF_DECL (x))
|
||
|
|
+ : 1);
|
||
|
|
+ size = (SYMBOL_REF_DECL (x) && DECL_SIZE (SYMBOL_REF_DECL (x))
|
||
|
|
+ ? tree_to_uhwi (DECL_SIZE (SYMBOL_REF_DECL (x)))
|
||
|
|
+ : 2*BITS_PER_WORD);
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ {
|
||
|
|
+ align = GET_MODE_ALIGNMENT (mode);
|
||
|
|
+ size = GET_MODE_BITSIZE (mode);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /* We may need to split multiword moves, so make sure that each word
|
||
|
|
+ can be accessed without inducing a carry. */
|
||
|
|
+ if (size > BITS_PER_WORD
|
||
|
|
+ && (!TARGET_STRICT_ALIGN || size > align))
|
||
|
|
+ return false;
|
||
|
|
+
|
||
|
|
+ return true;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
static bool
|
||
|
|
loongarch_valid_index_p (struct loongarch_address_info *info, rtx x,
|
||
|
|
machine_mode mode, bool strict_p)
|
||
|
|
@@ -1880,6 +1978,26 @@ loongarch_classify_address (struct loongarch_address_info *info, rtx x,
|
||
|
|
info->offset = XEXP (x, 1);
|
||
|
|
return (loongarch_valid_base_register_p (info->reg, mode, strict_p)
|
||
|
|
&& loongarch_valid_offset_p (info->offset, mode));
|
||
|
|
+
|
||
|
|
+ case LO_SUM:
|
||
|
|
+ info->type = ADDRESS_LO_SUM;
|
||
|
|
+ info->reg = XEXP (x, 0);
|
||
|
|
+ info->offset = XEXP (x, 1);
|
||
|
|
+ /* We have to trust the creator of the LO_SUM to do something vaguely
|
||
|
|
+ sane. Target-independent code that creates a LO_SUM should also
|
||
|
|
+ create and verify the matching HIGH. Target-independent code that
|
||
|
|
+ adds an offset to a LO_SUM must prove that the offset will not
|
||
|
|
+ induce a carry. Failure to do either of these things would be
|
||
|
|
+ a bug, and we are not required to check for it here. The MIPS
|
||
|
|
+ backend itself should only create LO_SUMs for valid symbolic
|
||
|
|
+ constants, with the high part being either a HIGH or a copy
|
||
|
|
+ of _gp. */
|
||
|
|
+ info->symbol_type
|
||
|
|
+ = loongarch_classify_symbolic_expression (info->offset);
|
||
|
|
+ return (loongarch_valid_base_register_p (info->reg, mode, strict_p)
|
||
|
|
+ && loongarch_valid_lo_sum_p (info->symbol_type, mode,
|
||
|
|
+ info->offset));
|
||
|
|
+
|
||
|
|
default:
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
@@ -1940,6 +2058,9 @@ loongarch_address_insns (rtx x, machine_mode mode, bool might_split_p)
|
||
|
|
case ADDRESS_CONST_INT:
|
||
|
|
return factor;
|
||
|
|
|
||
|
|
+ case ADDRESS_LO_SUM:
|
||
|
|
+ return factor + 1;
|
||
|
|
+
|
||
|
|
case ADDRESS_SYMBOLIC:
|
||
|
|
return factor * loongarch_symbol_insns (addr.symbol_type, mode);
|
||
|
|
}
|
||
|
|
@@ -1967,7 +2088,8 @@ loongarch_signed_immediate_p (unsigned HOST_WIDE_INT x, int bits,
|
||
|
|
return loongarch_unsigned_immediate_p (x, bits, shift);
|
||
|
|
}
|
||
|
|
|
||
|
|
-/* Return true if X is a legitimate address with a 12-bit offset.
|
||
|
|
+/* Return true if X is a legitimate address with a 12-bit offset
|
||
|
|
+ or addr.type is ADDRESS_LO_SUM.
|
||
|
|
MODE is the mode of the value being accessed. */
|
||
|
|
|
||
|
|
bool
|
||
|
|
@@ -1976,9 +2098,10 @@ loongarch_12bit_offset_address_p (rtx x, machine_mode mode)
|
||
|
|
struct loongarch_address_info addr;
|
||
|
|
|
||
|
|
return (loongarch_classify_address (&addr, x, mode, false)
|
||
|
|
- && addr.type == ADDRESS_REG
|
||
|
|
- && CONST_INT_P (addr.offset)
|
||
|
|
- && LARCH_12BIT_OFFSET_P (INTVAL (addr.offset)));
|
||
|
|
+ && ((addr.type == ADDRESS_REG
|
||
|
|
+ && CONST_INT_P (addr.offset)
|
||
|
|
+ && LARCH_12BIT_OFFSET_P (INTVAL (addr.offset)))
|
||
|
|
+ || addr.type == ADDRESS_LO_SUM));
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Return true if X is a legitimate address with a 14-bit offset shifted 2.
|
||
|
|
@@ -2020,6 +2143,14 @@ loongarch_const_insns (rtx x)
|
||
|
|
|
||
|
|
switch (GET_CODE (x))
|
||
|
|
{
|
||
|
|
+ case HIGH:
|
||
|
|
+ if (!loongarch_symbolic_constant_p (XEXP (x, 0), &symbol_type)
|
||
|
|
+ || !loongarch_split_symbol_type (symbol_type))
|
||
|
|
+ return 0;
|
||
|
|
+
|
||
|
|
+ /* This is simply a PCALAU12I. */
|
||
|
|
+ return 1;
|
||
|
|
+
|
||
|
|
case CONST_INT:
|
||
|
|
return loongarch_integer_cost (INTVAL (x));
|
||
|
|
|
||
|
|
@@ -2080,6 +2211,8 @@ loongarch_split_const_insns (rtx x)
|
||
|
|
return low + high;
|
||
|
|
}
|
||
|
|
|
||
|
|
+static bool loongarch_split_move_insn_p (rtx dest, rtx src);
|
||
|
|
+
|
||
|
|
/* Return the number of instructions needed to implement INSN,
|
||
|
|
given that it loads from or stores to MEM. */
|
||
|
|
|
||
|
|
@@ -2197,6 +2330,15 @@ loongarch_unspec_address (rtx address, enum loongarch_symbol_type symbol_type)
|
||
|
|
return loongarch_unspec_address_offset (base, offset, symbol_type);
|
||
|
|
}
|
||
|
|
|
||
|
|
+/* Emit an instruction of the form (set TARGET SRC). */
|
||
|
|
+
|
||
|
|
+static rtx
|
||
|
|
+loongarch_emit_set (rtx target, rtx src)
|
||
|
|
+{
|
||
|
|
+ emit_insn (gen_rtx_SET (target, src));
|
||
|
|
+ return target;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
/* If OP is an UNSPEC address, return the address to which it refers,
|
||
|
|
otherwise return OP itself. */
|
||
|
|
|
||
|
|
@@ -2278,6 +2420,7 @@ loongarch_call_tls_get_addr (rtx sym, enum loongarch_symbol_type type, rtx v0)
|
||
|
|
{
|
||
|
|
rtx loc, a0;
|
||
|
|
rtx_insn *insn;
|
||
|
|
+ rtx tmp = gen_reg_rtx (Pmode);
|
||
|
|
|
||
|
|
a0 = gen_rtx_REG (Pmode, GP_ARG_FIRST);
|
||
|
|
|
||
|
|
@@ -2288,12 +2431,22 @@ loongarch_call_tls_get_addr (rtx sym, enum loongarch_symbol_type type, rtx v0)
|
||
|
|
|
||
|
|
start_sequence ();
|
||
|
|
|
||
|
|
- if (type == SYMBOL_TLSLDM)
|
||
|
|
- emit_insn (loongarch_got_load_tls_ld (a0, loc));
|
||
|
|
- else if (type == SYMBOL_TLSGD)
|
||
|
|
- emit_insn (loongarch_got_load_tls_gd (a0, loc));
|
||
|
|
+ if (TARGET_EXPLICIT_RELOCS)
|
||
|
|
+ {
|
||
|
|
+ /* Split tls symbol to high and low. */
|
||
|
|
+ rtx high = gen_rtx_HIGH (Pmode, copy_rtx (loc));
|
||
|
|
+ high = loongarch_force_temporary (tmp, high);
|
||
|
|
+ emit_insn (gen_tls_low (Pmode, a0, high, loc));
|
||
|
|
+ }
|
||
|
|
else
|
||
|
|
- gcc_unreachable ();
|
||
|
|
+ {
|
||
|
|
+ if (type == SYMBOL_TLSLDM)
|
||
|
|
+ emit_insn (loongarch_got_load_tls_ld (a0, loc));
|
||
|
|
+ else if (type == SYMBOL_TLSGD)
|
||
|
|
+ emit_insn (loongarch_got_load_tls_gd (a0, loc));
|
||
|
|
+ else
|
||
|
|
+ gcc_unreachable ();
|
||
|
|
+ }
|
||
|
|
|
||
|
|
insn = emit_call_insn (gen_call_value_internal (v0, loongarch_tls_symbol,
|
||
|
|
const0_rtx));
|
||
|
|
@@ -2308,12 +2461,12 @@ loongarch_call_tls_get_addr (rtx sym, enum loongarch_symbol_type type, rtx v0)
|
||
|
|
|
||
|
|
/* Generate the code to access LOC, a thread-local SYMBOL_REF, and return
|
||
|
|
its address. The return value will be both a valid address and a valid
|
||
|
|
- SET_SRC. */
|
||
|
|
+ SET_SRC (either a REG or a LO_SUM). */
|
||
|
|
|
||
|
|
static rtx
|
||
|
|
loongarch_legitimize_tls_address (rtx loc)
|
||
|
|
{
|
||
|
|
- rtx dest, tp, tmp;
|
||
|
|
+ rtx dest, tp, tmp, tmp1, tmp2, tmp3;
|
||
|
|
enum tls_model model = SYMBOL_REF_TLS_MODEL (loc);
|
||
|
|
rtx_insn *insn;
|
||
|
|
|
||
|
|
@@ -2334,21 +2487,45 @@ loongarch_legitimize_tls_address (rtx loc)
|
||
|
|
break;
|
||
|
|
|
||
|
|
case TLS_MODEL_INITIAL_EXEC:
|
||
|
|
- /* la.tls.ie; tp-relative add. */
|
||
|
|
- tp = gen_rtx_REG (Pmode, THREAD_POINTER_REGNUM);
|
||
|
|
- tmp = gen_reg_rtx (Pmode);
|
||
|
|
- emit_insn (loongarch_got_load_tls_ie (tmp, loc));
|
||
|
|
- dest = gen_reg_rtx (Pmode);
|
||
|
|
- emit_insn (gen_add3_insn (dest, tmp, tp));
|
||
|
|
+ {
|
||
|
|
+ /* la.tls.ie; tp-relative add. */
|
||
|
|
+ tp = gen_rtx_REG (Pmode, THREAD_POINTER_REGNUM);
|
||
|
|
+ tmp1 = gen_reg_rtx (Pmode);
|
||
|
|
+ dest = gen_reg_rtx (Pmode);
|
||
|
|
+ if (TARGET_EXPLICIT_RELOCS)
|
||
|
|
+ {
|
||
|
|
+ tmp2 = loongarch_unspec_address (loc, SYMBOL_TLS_IE);
|
||
|
|
+ tmp3 = gen_reg_rtx (Pmode);
|
||
|
|
+ rtx high = gen_rtx_HIGH (Pmode, copy_rtx (tmp2));
|
||
|
|
+ high = loongarch_force_temporary (tmp3, high);
|
||
|
|
+ emit_insn (gen_ld_from_got (Pmode, tmp1, high, tmp2));
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ emit_insn (loongarch_got_load_tls_ie (tmp1, loc));
|
||
|
|
+ emit_insn (gen_add3_insn (dest, tmp1, tp));
|
||
|
|
+ }
|
||
|
|
break;
|
||
|
|
|
||
|
|
case TLS_MODEL_LOCAL_EXEC:
|
||
|
|
- /* la.tls.le; tp-relative add. */
|
||
|
|
- tp = gen_rtx_REG (Pmode, THREAD_POINTER_REGNUM);
|
||
|
|
- tmp = gen_reg_rtx (Pmode);
|
||
|
|
- emit_insn (loongarch_got_load_tls_le (tmp, loc));
|
||
|
|
- dest = gen_reg_rtx (Pmode);
|
||
|
|
- emit_insn (gen_add3_insn (dest, tmp, tp));
|
||
|
|
+ {
|
||
|
|
+ /* la.tls.le; tp-relative add. */
|
||
|
|
+ tp = gen_rtx_REG (Pmode, THREAD_POINTER_REGNUM);
|
||
|
|
+ tmp1 = gen_reg_rtx (Pmode);
|
||
|
|
+ dest = gen_reg_rtx (Pmode);
|
||
|
|
+
|
||
|
|
+ if (TARGET_EXPLICIT_RELOCS)
|
||
|
|
+ {
|
||
|
|
+ tmp2 = loongarch_unspec_address (loc, SYMBOL_TLS_LE);
|
||
|
|
+ tmp3 = gen_reg_rtx (Pmode);
|
||
|
|
+ rtx high = gen_rtx_HIGH (Pmode, copy_rtx (tmp2));
|
||
|
|
+ high = loongarch_force_temporary (tmp3, high);
|
||
|
|
+ emit_insn (gen_ori_l_lo12 (Pmode, tmp1, high, tmp2));
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ emit_insn (loongarch_got_load_tls_le (tmp1, loc));
|
||
|
|
+ emit_insn (gen_add3_insn (dest, tmp1, tp));
|
||
|
|
+
|
||
|
|
+ }
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
@@ -2397,6 +2574,68 @@ loongarch_force_address (rtx x, machine_mode mode)
|
||
|
|
return x;
|
||
|
|
}
|
||
|
|
|
||
|
|
+/* 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.
|
||
|
|
+ If so, and if LOW_OUT is nonnull, emit the high part and store the
|
||
|
|
+ low part in *LOW_OUT. Leave *LOW_OUT unchanged otherwise.
|
||
|
|
+
|
||
|
|
+ Return false if build with '-mno-explicit-relocs'.
|
||
|
|
+
|
||
|
|
+ TEMP is as for loongarch_force_temporary and is used to load the high
|
||
|
|
+ part into a register.
|
||
|
|
+
|
||
|
|
+ When MODE is MAX_MACHINE_MODE, the low part is guaranteed to be
|
||
|
|
+ a legitimize SET_SRC for an .md pattern, otherwise the low part
|
||
|
|
+ is guaranteed to be a legitimate address for mode MODE. */
|
||
|
|
+
|
||
|
|
+bool
|
||
|
|
+loongarch_split_symbol (rtx temp, rtx addr, machine_mode mode, rtx *low_out)
|
||
|
|
+{
|
||
|
|
+ enum loongarch_symbol_type symbol_type;
|
||
|
|
+ rtx high;
|
||
|
|
+
|
||
|
|
+ /* If build with '-mno-explicit-relocs', don't split symbol. */
|
||
|
|
+ if (!TARGET_EXPLICIT_RELOCS)
|
||
|
|
+ return false;
|
||
|
|
+
|
||
|
|
+ if ((GET_CODE (addr) == HIGH && mode == MAX_MACHINE_MODE)
|
||
|
|
+ || !loongarch_symbolic_constant_p (addr, &symbol_type)
|
||
|
|
+ || loongarch_symbol_insns (symbol_type, mode) == 0
|
||
|
|
+ || !loongarch_split_symbol_type (symbol_type))
|
||
|
|
+ return false;
|
||
|
|
+
|
||
|
|
+ if (temp == NULL)
|
||
|
|
+ temp = gen_reg_rtx (Pmode);
|
||
|
|
+
|
||
|
|
+ /* Get the 12-31 bits of the address. */
|
||
|
|
+ high = gen_rtx_HIGH (Pmode, copy_rtx (addr));
|
||
|
|
+ high = loongarch_force_temporary (temp, high);
|
||
|
|
+
|
||
|
|
+ if (low_out)
|
||
|
|
+ switch (symbol_type)
|
||
|
|
+ {
|
||
|
|
+ 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. */
|
||
|
|
+ {
|
||
|
|
+ rtx low = gen_rtx_LO_SUM (Pmode, high, addr);
|
||
|
|
+ rtx mem = gen_rtx_MEM (Pmode, low);
|
||
|
|
+ *low_out = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, mem),
|
||
|
|
+ UNSPEC_LOAD_FROM_GOT);
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ default:
|
||
|
|
+ gcc_unreachable ();
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return true;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
/* This function is used to implement LEGITIMIZE_ADDRESS. If X can
|
||
|
|
be legitimized in a way that the generic machinery might not expect,
|
||
|
|
return a new address, otherwise return NULL. MODE is the mode of
|
||
|
|
@@ -2412,6 +2651,10 @@ loongarch_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
|
||
|
|
if (loongarch_tls_symbol_p (x))
|
||
|
|
return loongarch_legitimize_tls_address (x);
|
||
|
|
|
||
|
|
+ /* See if the address can split into a high part and a LO_SUM. */
|
||
|
|
+ if (loongarch_split_symbol (NULL, x, mode, &addr))
|
||
|
|
+ return loongarch_force_address (addr, mode);
|
||
|
|
+
|
||
|
|
/* Handle BASE + OFFSET using loongarch_add_offset. */
|
||
|
|
loongarch_split_plus (x, &base, &offset);
|
||
|
|
if (offset != 0)
|
||
|
|
@@ -2499,6 +2742,13 @@ loongarch_legitimize_const_move (machine_mode mode, rtx dest, rtx src)
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ /* Split moves of symbolic constants into high and low. */
|
||
|
|
+ if (loongarch_split_symbol (dest, src, MAX_MACHINE_MODE, &src))
|
||
|
|
+ {
|
||
|
|
+ loongarch_emit_set (dest, src);
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
/* Generate the appropriate access sequences for TLS symbols. */
|
||
|
|
if (loongarch_tls_symbol_p (src))
|
||
|
|
{
|
||
|
|
@@ -3241,21 +3491,12 @@ loongarch_split_move (rtx dest, rtx src, rtx insn_)
|
||
|
|
|
||
|
|
/* Return true if a move from SRC to DEST in INSN should be split. */
|
||
|
|
|
||
|
|
-bool
|
||
|
|
+static bool
|
||
|
|
loongarch_split_move_insn_p (rtx dest, rtx src)
|
||
|
|
{
|
||
|
|
return loongarch_split_move_p (dest, src);
|
||
|
|
}
|
||
|
|
|
||
|
|
-/* Split a move from SRC to DEST in INSN, given that
|
||
|
|
- loongarch_split_move_insn_p holds. */
|
||
|
|
-
|
||
|
|
-void
|
||
|
|
-loongarch_split_move_insn (rtx dest, rtx src, rtx insn)
|
||
|
|
-{
|
||
|
|
- loongarch_split_move (dest, src, insn);
|
||
|
|
-}
|
||
|
|
-
|
||
|
|
/* Implement TARGET_CONSTANT_ALIGNMENT. */
|
||
|
|
|
||
|
|
static HOST_WIDE_INT
|
||
|
|
@@ -3369,13 +3610,16 @@ loongarch_output_move (rtx dest, rtx src)
|
||
|
|
case 2:
|
||
|
|
return "st.h\t%z1,%0";
|
||
|
|
case 4:
|
||
|
|
- /* Matching address type with a 12bit offset. */
|
||
|
|
- if (const_arith_operand (offset, Pmode))
|
||
|
|
+ /* Matching address type with a 12bit offset and
|
||
|
|
+ ADDRESS_LO_SUM. */
|
||
|
|
+ if (const_arith_operand (offset, Pmode)
|
||
|
|
+ || GET_CODE (offset) == LO_SUM)
|
||
|
|
return "st.w\t%z1,%0";
|
||
|
|
else
|
||
|
|
return "stptr.w\t%z1,%0";
|
||
|
|
case 8:
|
||
|
|
- if (const_arith_operand (offset, Pmode))
|
||
|
|
+ if (const_arith_operand (offset, Pmode)
|
||
|
|
+ || GET_CODE (offset) == LO_SUM)
|
||
|
|
return "st.d\t%z1,%0";
|
||
|
|
else
|
||
|
|
return "stptr.d\t%z1,%0";
|
||
|
|
@@ -3408,13 +3652,16 @@ loongarch_output_move (rtx dest, rtx src)
|
||
|
|
case 2:
|
||
|
|
return "ld.hu\t%0,%1";
|
||
|
|
case 4:
|
||
|
|
- /* Matching address type with a 12bit offset. */
|
||
|
|
- if (const_arith_operand (offset, Pmode))
|
||
|
|
+ /* Matching address type with a 12bit offset and
|
||
|
|
+ ADDRESS_LO_SUM. */
|
||
|
|
+ if (const_arith_operand (offset, Pmode)
|
||
|
|
+ || GET_CODE (offset) == LO_SUM)
|
||
|
|
return "ld.w\t%0,%1";
|
||
|
|
else
|
||
|
|
return "ldptr.w\t%0,%1";
|
||
|
|
case 8:
|
||
|
|
- if (const_arith_operand (offset, Pmode))
|
||
|
|
+ if (const_arith_operand (offset, Pmode)
|
||
|
|
+ || GET_CODE (offset) == LO_SUM)
|
||
|
|
return "ld.d\t%0,%1";
|
||
|
|
else
|
||
|
|
return "ldptr.d\t%0,%1";
|
||
|
|
@@ -3423,6 +3670,21 @@ loongarch_output_move (rtx dest, rtx src)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
+ if (src_code == HIGH)
|
||
|
|
+ {
|
||
|
|
+ rtx offset, x;
|
||
|
|
+ split_const (XEXP (src, 0), &x, &offset);
|
||
|
|
+ enum loongarch_symbol_type type = SYMBOL_PCREL;
|
||
|
|
+
|
||
|
|
+ if (UNSPEC_ADDRESS_P (x))
|
||
|
|
+ type = UNSPEC_ADDRESS_TYPE (x);
|
||
|
|
+
|
||
|
|
+ if (type == SYMBOL_TLS_LE)
|
||
|
|
+ return "lu12i.w\t%0,%h1";
|
||
|
|
+ else
|
||
|
|
+ return "pcalau12i\t%0,%h1";
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
if (src_code == CONST_INT)
|
||
|
|
{
|
||
|
|
if (LU12I_INT (src))
|
||
|
|
@@ -3438,7 +3700,8 @@ loongarch_output_move (rtx dest, rtx src)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
- if (dest_code == REG && symbolic_operand (src, VOIDmode))
|
||
|
|
+ if (!TARGET_EXPLICIT_RELOCS
|
||
|
|
+ && dest_code == REG && symbolic_operand (src, VOIDmode))
|
||
|
|
{
|
||
|
|
if (loongarch_classify_symbol (src) == SYMBOL_PCREL)
|
||
|
|
return "la.local\t%0,%1";
|
||
|
|
@@ -4307,6 +4570,49 @@ loongarch_memmodel_needs_release_fence (enum memmodel model)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
+/* Print symbolic operand OP, which is part of a HIGH or LO_SUM
|
||
|
|
+ in context CONTEXT. HI_RELOC indicates a high-part reloc. */
|
||
|
|
+
|
||
|
|
+static void
|
||
|
|
+loongarch_print_operand_reloc (FILE *file, rtx op, bool hi_reloc)
|
||
|
|
+{
|
||
|
|
+ const char *reloc;
|
||
|
|
+
|
||
|
|
+ switch (loongarch_classify_symbolic_expression (op))
|
||
|
|
+ {
|
||
|
|
+ case SYMBOL_PCREL:
|
||
|
|
+ reloc = hi_reloc ? "%pc_hi20" : "%pc_lo12";
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case SYMBOL_GOT_DISP:
|
||
|
|
+ reloc = hi_reloc ? "%got_pc_hi20" : "%got_pc_lo12";
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case SYMBOL_TLS_IE:
|
||
|
|
+ reloc = hi_reloc ? "%ie_pc_hi20" : "%ie_pc_lo12";
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case SYMBOL_TLS_LE:
|
||
|
|
+ reloc = hi_reloc ? "%le_hi20" : "%le_lo12";
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case SYMBOL_TLSGD:
|
||
|
|
+ reloc = hi_reloc ? "%gd_pc_hi20" : "%got_pc_lo12";
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case SYMBOL_TLSLDM:
|
||
|
|
+ reloc = hi_reloc ? "%ld_pc_hi20" : "%got_pc_lo12";
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ default:
|
||
|
|
+ gcc_unreachable ();
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ fprintf (file, "%s(", reloc);
|
||
|
|
+ output_addr_const (file, loongarch_strip_unspec_address (op));
|
||
|
|
+ fputc (')', file);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
/* Implement TARGET_PRINT_OPERAND. The LoongArch-specific operand codes are:
|
||
|
|
|
||
|
|
'A' Print a _DB suffix if the memory model requires a release.
|
||
|
|
@@ -4315,7 +4621,10 @@ loongarch_memmodel_needs_release_fence (enum memmodel model)
|
||
|
|
'd' Print CONST_INT OP in decimal.
|
||
|
|
'F' Print the FPU branch condition for comparison OP.
|
||
|
|
'G' Print a DBAR insn if the memory model requires a release.
|
||
|
|
+ 'H' Print address 52-61bit relocation associated with OP.
|
||
|
|
+ 'h' Print the high-part relocation associated with OP.
|
||
|
|
'i' Print i if the operand is not a register.
|
||
|
|
+ 'L' Print the low-part relocation associated with OP.
|
||
|
|
'm' Print one less than CONST_INT OP in decimal.
|
||
|
|
'N' Print the inverse of the integer branch condition for comparison OP.
|
||
|
|
'T' Print 'f' for (eq:CC ...), 't' for (ne:CC ...),
|
||
|
|
@@ -4372,11 +4681,21 @@ loongarch_print_operand (FILE *file, rtx op, int letter)
|
||
|
|
fputs ("dbar\t0", file);
|
||
|
|
break;
|
||
|
|
|
||
|
|
+ case 'h':
|
||
|
|
+ if (code == HIGH)
|
||
|
|
+ op = XEXP (op, 0);
|
||
|
|
+ loongarch_print_operand_reloc (file, op, true /* hi_reloc */);
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
case 'i':
|
||
|
|
if (code != REG)
|
||
|
|
fputs ("i", file);
|
||
|
|
break;
|
||
|
|
|
||
|
|
+ case 'L':
|
||
|
|
+ loongarch_print_operand_reloc (file, op, false /* lo_reloc */);
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
case 'm':
|
||
|
|
if (CONST_INT_P (op))
|
||
|
|
fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (op) - 1);
|
||
|
|
@@ -4517,6 +4836,11 @@ loongarch_print_operand_address (FILE *file, machine_mode /* mode */, rtx x)
|
||
|
|
reg_names[REGNO (addr.offset)]);
|
||
|
|
return;
|
||
|
|
|
||
|
|
+ case ADDRESS_LO_SUM:
|
||
|
|
+ fprintf (file, "%s,", reg_names[REGNO (addr.reg)]);
|
||
|
|
+ loongarch_print_operand_reloc (file, addr.offset, false /* hi_reloc */);
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
case ADDRESS_CONST_INT:
|
||
|
|
fprintf (file, "%s,", reg_names[GP_REG_FIRST]);
|
||
|
|
output_addr_const (file, x);
|
||
|
|
@@ -5891,6 +6215,12 @@ loongarch_starting_frame_offset (void)
|
||
|
|
#undef TARGET_TRAMPOLINE_INIT
|
||
|
|
#define TARGET_TRAMPOLINE_INIT loongarch_trampoline_init
|
||
|
|
|
||
|
|
+#undef TARGET_MIN_ANCHOR_OFFSET
|
||
|
|
+#define TARGET_MIN_ANCHOR_OFFSET (-IMM_REACH/2)
|
||
|
|
+
|
||
|
|
+#undef TARGET_MAX_ANCHOR_OFFSET
|
||
|
|
+#define TARGET_MAX_ANCHOR_OFFSET (IMM_REACH/2-1)
|
||
|
|
+
|
||
|
|
#undef TARGET_ATOMIC_ASSIGN_EXPAND_FENV
|
||
|
|
#define TARGET_ATOMIC_ASSIGN_EXPAND_FENV loongarch_atomic_assign_expand_fenv
|
||
|
|
|
||
|
|
diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md
|
||
|
|
index 376879fbc..6b6df22a5 100644
|
||
|
|
--- a/gcc/config/loongarch/loongarch.md
|
||
|
|
+++ b/gcc/config/loongarch/loongarch.md
|
||
|
|
@@ -57,6 +57,10 @@
|
||
|
|
;; CRC
|
||
|
|
UNSPEC_CRC
|
||
|
|
UNSPEC_CRCC
|
||
|
|
+
|
||
|
|
+ UNSPEC_LOAD_FROM_GOT
|
||
|
|
+ UNSPEC_ORI_L_LO12
|
||
|
|
+ UNSPEC_TLS_LOW
|
||
|
|
])
|
||
|
|
|
||
|
|
(define_c_enum "unspecv" [
|
||
|
|
@@ -1743,73 +1747,6 @@
|
||
|
|
[(set_attr "move_type" "move,load,store")
|
||
|
|
(set_attr "mode" "DF")])
|
||
|
|
|
||
|
|
-
|
||
|
|
-;; 128-bit integer moves
|
||
|
|
-
|
||
|
|
-(define_expand "movti"
|
||
|
|
- [(set (match_operand:TI 0)
|
||
|
|
- (match_operand:TI 1))]
|
||
|
|
- "TARGET_64BIT"
|
||
|
|
-{
|
||
|
|
- if (loongarch_legitimize_move (TImode, operands[0], operands[1]))
|
||
|
|
- DONE;
|
||
|
|
-})
|
||
|
|
-
|
||
|
|
-(define_insn "*movti"
|
||
|
|
- [(set (match_operand:TI 0 "nonimmediate_operand" "=r,r,r,m")
|
||
|
|
- (match_operand:TI 1 "move_operand" "r,i,m,rJ"))]
|
||
|
|
- "TARGET_64BIT
|
||
|
|
- && (register_operand (operands[0], TImode)
|
||
|
|
- || reg_or_0_operand (operands[1], TImode))"
|
||
|
|
- { return loongarch_output_move (operands[0], operands[1]); }
|
||
|
|
- [(set_attr "move_type" "move,const,load,store")
|
||
|
|
- (set (attr "mode")
|
||
|
|
- (if_then_else (eq_attr "move_type" "imul")
|
||
|
|
- (const_string "SI")
|
||
|
|
- (const_string "TI")))])
|
||
|
|
-
|
||
|
|
-;; 128-bit floating point moves
|
||
|
|
-
|
||
|
|
-(define_expand "movtf"
|
||
|
|
- [(set (match_operand:TF 0)
|
||
|
|
- (match_operand:TF 1))]
|
||
|
|
- "TARGET_64BIT"
|
||
|
|
-{
|
||
|
|
- if (loongarch_legitimize_move (TFmode, operands[0], operands[1]))
|
||
|
|
- DONE;
|
||
|
|
-})
|
||
|
|
-
|
||
|
|
-;; This pattern handles both hard- and soft-float cases.
|
||
|
|
-(define_insn "*movtf"
|
||
|
|
- [(set (match_operand:TF 0 "nonimmediate_operand" "=r,r,m,f,r,f,m")
|
||
|
|
- (match_operand:TF 1 "move_operand" "rG,m,rG,rG,f,m,f"))]
|
||
|
|
- "TARGET_64BIT
|
||
|
|
- && (register_operand (operands[0], TFmode)
|
||
|
|
- || reg_or_0_operand (operands[1], TFmode))"
|
||
|
|
- "#"
|
||
|
|
- [(set_attr "move_type" "move,load,store,mgtf,mftg,fpload,fpstore")
|
||
|
|
- (set_attr "mode" "TF")])
|
||
|
|
-
|
||
|
|
-(define_split
|
||
|
|
- [(set (match_operand:MOVE64 0 "nonimmediate_operand")
|
||
|
|
- (match_operand:MOVE64 1 "move_operand"))]
|
||
|
|
- "reload_completed && loongarch_split_move_insn_p (operands[0], operands[1])"
|
||
|
|
- [(const_int 0)]
|
||
|
|
-{
|
||
|
|
- loongarch_split_move_insn (operands[0], operands[1], curr_insn);
|
||
|
|
- DONE;
|
||
|
|
-})
|
||
|
|
-
|
||
|
|
-(define_split
|
||
|
|
- [(set (match_operand:MOVE128 0 "nonimmediate_operand")
|
||
|
|
- (match_operand:MOVE128 1 "move_operand"))]
|
||
|
|
- "reload_completed && loongarch_split_move_insn_p (operands[0], operands[1])"
|
||
|
|
- [(const_int 0)]
|
||
|
|
-{
|
||
|
|
- loongarch_split_move_insn (operands[0], operands[1], curr_insn);
|
||
|
|
- DONE;
|
||
|
|
-})
|
||
|
|
-
|
||
|
|
;; Emit a doubleword move in which exactly one of the operands is
|
||
|
|
;; a floating-point register. We can't just emit two normal moves
|
||
|
|
;; because of the constraints imposed by the FPU register model;
|
||
|
|
@@ -1938,6 +1875,57 @@
|
||
|
|
[(set_attr "type" "arith")
|
||
|
|
(set_attr "mode" "DI")])
|
||
|
|
|
||
|
|
+;; Instructions for adding the low 12 bits of an address to a register.
|
||
|
|
+;; Operand 2 is the address: loongarch_print_operand works out which relocation
|
||
|
|
+;; should be applied.
|
||
|
|
+
|
||
|
|
+(define_insn "*low<mode>"
|
||
|
|
+ [(set (match_operand:P 0 "register_operand" "=r")
|
||
|
|
+ (lo_sum:P (match_operand:P 1 "register_operand" " r")
|
||
|
|
+ (match_operand:P 2 "symbolic_operand" "")))]
|
||
|
|
+ "TARGET_EXPLICIT_RELOCS"
|
||
|
|
+ "addi.<d>\t%0,%1,%L2"
|
||
|
|
+ [(set_attr "type" "arith")
|
||
|
|
+ (set_attr "mode" "<MODE>")])
|
||
|
|
+
|
||
|
|
+(define_insn "@tls_low<mode>"
|
||
|
|
+ [(set (match_operand:P 0 "register_operand" "=r")
|
||
|
|
+ (unspec:P [(mem:P (lo_sum:P (match_operand:P 1 "register_operand" "r")
|
||
|
|
+ (match_operand:P 2 "symbolic_operand" "")))]
|
||
|
|
+ UNSPEC_TLS_LOW))]
|
||
|
|
+ "TARGET_EXPLICIT_RELOCS"
|
||
|
|
+ "addi.<d>\t%0,%1,%L2"
|
||
|
|
+ [(set_attr "type" "arith")
|
||
|
|
+ (set_attr "mode" "<MODE>")])
|
||
|
|
+
|
||
|
|
+;; Instructions for loading address from GOT entry.
|
||
|
|
+;; operands[1] is pc plus the high half of the address difference with the got
|
||
|
|
+;; entry;
|
||
|
|
+;; operands[2] is low 12 bits for low 12 bit of the address difference with the
|
||
|
|
+;; got entry.
|
||
|
|
+;; loongarch_print_operand works out which relocation should be applied.
|
||
|
|
+
|
||
|
|
+(define_insn "@ld_from_got<mode>"
|
||
|
|
+ [(set (match_operand:P 0 "register_operand" "=r")
|
||
|
|
+ (unspec:P [(mem:P (lo_sum:P
|
||
|
|
+ (match_operand:P 1 "register_operand" "r")
|
||
|
|
+ (match_operand:P 2 "symbolic_operand")))]
|
||
|
|
+ UNSPEC_LOAD_FROM_GOT))]
|
||
|
|
+ "TARGET_EXPLICIT_RELOCS"
|
||
|
|
+ "ld.<d>\t%0,%1,%L2"
|
||
|
|
+ [(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")
|
||
|
|
+ (match_operand:P 2 "symbolic_operand")]
|
||
|
|
+ UNSPEC_ORI_L_LO12))]
|
||
|
|
+ ""
|
||
|
|
+ "ori\t%0,%1,%L2"
|
||
|
|
+ [(set_attr "type" "move")]
|
||
|
|
+)
|
||
|
|
+
|
||
|
|
;; Convert floating-point numbers to integers
|
||
|
|
(define_insn "frint_<fmt>"
|
||
|
|
[(set (match_operand:ANYF 0 "register_operand" "=f")
|
||
|
|
diff --git a/gcc/config/loongarch/loongarch.opt b/gcc/config/loongarch/loongarch.opt
|
||
|
|
index 3ff0d8604..7a8c5b444 100644
|
||
|
|
--- a/gcc/config/loongarch/loongarch.opt
|
||
|
|
+++ b/gcc/config/loongarch/loongarch.opt
|
||
|
|
@@ -161,6 +161,10 @@ mmax-inline-memcpy-size=
|
||
|
|
Target Joined RejectNegative UInteger Var(loongarch_max_inline_memcpy_size) Init(1024)
|
||
|
|
-mmax-inline-memcpy-size=SIZE Set the max size of memcpy to inline, default is 1024.
|
||
|
|
|
||
|
|
+mexplicit-relocs
|
||
|
|
+Target Var(TARGET_EXPLICIT_RELOCS) Init(1)
|
||
|
|
+Use %reloc() assembly operators.
|
||
|
|
+
|
||
|
|
; The code model option names for -mcmodel.
|
||
|
|
Enum
|
||
|
|
Name(cmodel) Type(int)
|
||
|
|
diff --git a/gcc/config/loongarch/predicates.md b/gcc/config/loongarch/predicates.md
|
||
|
|
index 2243ef71c..cd3528c7c 100644
|
||
|
|
--- a/gcc/config/loongarch/predicates.md
|
||
|
|
+++ b/gcc/config/loongarch/predicates.md
|
||
|
|
@@ -110,6 +110,10 @@
|
||
|
|
(define_predicate "const_call_insn_operand"
|
||
|
|
(match_code "const,symbol_ref,label_ref")
|
||
|
|
{
|
||
|
|
+ /* Split symbol to high and low if return false.
|
||
|
|
+ If defined TARGET_CMODEL_LARGE, all symbol would be splited,
|
||
|
|
+ else if offset is not zero, the symbol would be splited. */
|
||
|
|
+
|
||
|
|
enum loongarch_symbol_type symbol_type;
|
||
|
|
loongarch_symbolic_constant_p (op, &symbol_type);
|
||
|
|
|
||
|
|
@@ -125,7 +129,7 @@
|
||
|
|
return 1;
|
||
|
|
|
||
|
|
case SYMBOL_GOT_DISP:
|
||
|
|
- if (!flag_plt)
|
||
|
|
+ if (TARGET_CMODEL_LARGE || !flag_plt)
|
||
|
|
return false;
|
||
|
|
else
|
||
|
|
return 1;
|
||
|
|
@@ -213,7 +217,19 @@
|
||
|
|
case CONST:
|
||
|
|
case SYMBOL_REF:
|
||
|
|
case LABEL_REF:
|
||
|
|
- return loongarch_symbolic_constant_p (op, &symbol_type);
|
||
|
|
+ return (loongarch_symbolic_constant_p (op, &symbol_type)
|
||
|
|
+ && (!TARGET_EXPLICIT_RELOCS
|
||
|
|
+ || !loongarch_split_symbol_type (symbol_type)));
|
||
|
|
+
|
||
|
|
+ case HIGH:
|
||
|
|
+ /* '-mno-explicit-relocs' don't generate high/low pairs. */
|
||
|
|
+ if (!TARGET_EXPLICIT_RELOCS)
|
||
|
|
+ return false;
|
||
|
|
+
|
||
|
|
+ op = XEXP (op, 0);
|
||
|
|
+ return (loongarch_symbolic_constant_p (op, &symbol_type)
|
||
|
|
+ && loongarch_split_symbol_type (symbol_type));
|
||
|
|
+
|
||
|
|
default:
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-1.c b/gcc/testsuite/gcc.target/loongarch/func-call-1.c
|
||
|
|
index b0482761a..01b8ea23f 100644
|
||
|
|
--- a/gcc/testsuite/gcc.target/loongarch/func-call-1.c
|
||
|
|
+++ b/gcc/testsuite/gcc.target/loongarch/func-call-1.c
|
||
|
|
@@ -1,5 +1,5 @@
|
||
|
|
/* { dg-do compile } */
|
||
|
|
-/* { dg-options "-mabi=lp64d -O0 -fpic -fplt" } */
|
||
|
|
+/* { dg-options "-mabi=lp64d -O0 -fpic -fplt -mno-explicit-relocs" } */
|
||
|
|
/* { dg-final { scan-assembler "test:.*bl\t%plt\\(g\\)\n" } } */
|
||
|
|
/* { dg-final { scan-assembler "test1:.*bl\t%plt\\(f\\)\n" } } */
|
||
|
|
/* { dg-final { scan-assembler "test2:.*bl\tl\n" } } */
|
||
|
|
diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-2.c b/gcc/testsuite/gcc.target/loongarch/func-call-2.c
|
||
|
|
index f5e061c29..4565baaec 100644
|
||
|
|
--- a/gcc/testsuite/gcc.target/loongarch/func-call-2.c
|
||
|
|
+++ b/gcc/testsuite/gcc.target/loongarch/func-call-2.c
|
||
|
|
@@ -1,5 +1,5 @@
|
||
|
|
/* { dg-do compile } */
|
||
|
|
-/* { dg-options "-mabi=lp64d -O0 -fno-pic -fplt" } */
|
||
|
|
+/* { dg-options "-mabi=lp64d -O0 -fno-pic -fplt -mno-explicit-relocs" } */
|
||
|
|
/* { dg-final { scan-assembler "test:.*bl\t%plt\\(g\\)\n" } } */
|
||
|
|
/* { dg-final { scan-assembler "test1:.*bl\tf\n" } } */
|
||
|
|
/* { dg-final { scan-assembler "test2:.*bl\tl\n" } } */
|
||
|
|
diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-3.c b/gcc/testsuite/gcc.target/loongarch/func-call-3.c
|
||
|
|
index 75082c574..4f669a029 100644
|
||
|
|
--- a/gcc/testsuite/gcc.target/loongarch/func-call-3.c
|
||
|
|
+++ b/gcc/testsuite/gcc.target/loongarch/func-call-3.c
|
||
|
|
@@ -1,5 +1,5 @@
|
||
|
|
/* { dg-do compile } */
|
||
|
|
-/* { dg-options "-mabi=lp64d -O0 -fpic -fno-plt" } */
|
||
|
|
+/* { dg-options "-mabi=lp64d -O0 -fpic -fno-plt -mno-explicit-relocs" } */
|
||
|
|
/* { dg-final { scan-assembler "test:.*la\.global\t.*g\n\tjirl" } } */
|
||
|
|
/* { dg-final { scan-assembler "test1:.*la\.global\t.*f\n\tjirl" } } */
|
||
|
|
/* { dg-final { scan-assembler "test2:.*bl\tl\n" } } */
|
||
|
|
diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-4.c b/gcc/testsuite/gcc.target/loongarch/func-call-4.c
|
||
|
|
index e8a839549..943adb640 100644
|
||
|
|
--- a/gcc/testsuite/gcc.target/loongarch/func-call-4.c
|
||
|
|
+++ b/gcc/testsuite/gcc.target/loongarch/func-call-4.c
|
||
|
|
@@ -1,5 +1,5 @@
|
||
|
|
/* { dg-do compile } */
|
||
|
|
-/* { dg-options "-mabi=lp64d -O0 -fno-pic -fno-plt" } */
|
||
|
|
+/* { dg-options "-mabi=lp64d -O0 -fno-pic -fno-plt -mno-explicit-relocs" } */
|
||
|
|
/* { dg-final { scan-assembler "test:.*la\.global\t.*g\n\tjirl" } } */
|
||
|
|
/* { dg-final { scan-assembler "test1:.*bl\tf\n" } } */
|
||
|
|
/* { dg-final { scan-assembler "test2:.*bl\tl\n" } } */
|
||
|
|
diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-5.c b/gcc/testsuite/gcc.target/loongarch/func-call-5.c
|
||
|
|
new file mode 100644
|
||
|
|
index 000000000..2c2a1c8a1
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/gcc/testsuite/gcc.target/loongarch/func-call-5.c
|
||
|
|
@@ -0,0 +1,33 @@
|
||
|
|
+/* { dg-do compile } */
|
||
|
|
+/* { dg-options "-mabi=lp64d -O0 -fpic -fplt -mexplicit-relocs" } */
|
||
|
|
+/* { dg-final { scan-assembler "test:.*bl\t%plt\\(g\\)\n" } } */
|
||
|
|
+/* { dg-final { scan-assembler "test1:.*bl\t%plt\\(f\\)\n" } } */
|
||
|
|
+/* { dg-final { scan-assembler "test2:.*bl\tl\n" } } */
|
||
|
|
+
|
||
|
|
+extern void g (void);
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+f (void)
|
||
|
|
+{}
|
||
|
|
+
|
||
|
|
+static void
|
||
|
|
+l (void)
|
||
|
|
+{}
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+test (void)
|
||
|
|
+{
|
||
|
|
+ g ();
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+test1 (void)
|
||
|
|
+{
|
||
|
|
+ f ();
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+test2 (void)
|
||
|
|
+{
|
||
|
|
+ l ();
|
||
|
|
+}
|
||
|
|
diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-6.c b/gcc/testsuite/gcc.target/loongarch/func-call-6.c
|
||
|
|
new file mode 100644
|
||
|
|
index 000000000..4b0e4266e
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/gcc/testsuite/gcc.target/loongarch/func-call-6.c
|
||
|
|
@@ -0,0 +1,33 @@
|
||
|
|
+/* { dg-do compile } */
|
||
|
|
+/* { dg-options "-mabi=lp64d -O0 -fno-pic -fplt -mexplicit-relocs" } */
|
||
|
|
+/* { dg-final { scan-assembler "test:.*bl\t%plt\\(g\\)\n" } } */
|
||
|
|
+/* { dg-final { scan-assembler "test1:.*bl\tf\n" } } */
|
||
|
|
+/* { dg-final { scan-assembler "test2:.*bl\tl\n" } } */
|
||
|
|
+
|
||
|
|
+extern void g (void);
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+f (void)
|
||
|
|
+{}
|
||
|
|
+
|
||
|
|
+static void
|
||
|
|
+l (void)
|
||
|
|
+{}
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+test (void)
|
||
|
|
+{
|
||
|
|
+ g ();
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+test1 (void)
|
||
|
|
+{
|
||
|
|
+ f ();
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+test2 (void)
|
||
|
|
+{
|
||
|
|
+ l ();
|
||
|
|
+}
|
||
|
|
diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-7.c b/gcc/testsuite/gcc.target/loongarch/func-call-7.c
|
||
|
|
new file mode 100644
|
||
|
|
index 000000000..51792711f
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/gcc/testsuite/gcc.target/loongarch/func-call-7.c
|
||
|
|
@@ -0,0 +1,34 @@
|
||
|
|
+/* { dg-do compile } */
|
||
|
|
+/* { dg-options "-mabi=lp64d -O0 -fpic -fno-plt -mexplicit-relocs" } */
|
||
|
|
+/* { dg-final { scan-assembler "test:.*pcalau12i\t.*%got_pc_hi20\\(g\\)\n\tld\.d\t.*%got_pc_lo12\\(g\\)\n\tjirl" } } */
|
||
|
|
+/* { dg-final { scan-assembler "test1:.*pcalau12i\t.*%got_pc_hi20\\(f\\)\n\tld\.d\t.*%got_pc_lo12\\(f\\)\n\tjirl" } } */
|
||
|
|
+/* { dg-final { scan-assembler "test2:.*bl\tl\n" } } */
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+extern void g (void);
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+f (void)
|
||
|
|
+{}
|
||
|
|
+
|
||
|
|
+static void
|
||
|
|
+l (void)
|
||
|
|
+{}
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+test (void)
|
||
|
|
+{
|
||
|
|
+ g ();
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+test1 (void)
|
||
|
|
+{
|
||
|
|
+ f ();
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+test2 (void)
|
||
|
|
+{
|
||
|
|
+ l ();
|
||
|
|
+}
|
||
|
|
diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-8.c b/gcc/testsuite/gcc.target/loongarch/func-call-8.c
|
||
|
|
new file mode 100644
|
||
|
|
index 000000000..330140d88
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/gcc/testsuite/gcc.target/loongarch/func-call-8.c
|
||
|
|
@@ -0,0 +1,33 @@
|
||
|
|
+/* { dg-do compile } */
|
||
|
|
+/* { dg-options "-mabi=lp64d -O0 -fno-pic -fno-plt -mexplicit-relocs" } */
|
||
|
|
+/* { dg-final { scan-assembler "test:.*pcalau12i\t.*%got_pc_hi20\\(g\\)\n\tld\.d\t.*%got_pc_lo12\\(g\\)\n\tjirl" } } */
|
||
|
|
+/* { dg-final { scan-assembler "test1:.*bl\tf\n" } } */
|
||
|
|
+/* { dg-final { scan-assembler "test2:.*bl\tl\n" } } */
|
||
|
|
+
|
||
|
|
+extern void g (void);
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+f (void)
|
||
|
|
+{}
|
||
|
|
+
|
||
|
|
+static void
|
||
|
|
+l (void)
|
||
|
|
+{}
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+test (void)
|
||
|
|
+{
|
||
|
|
+ g ();
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+test1 (void)
|
||
|
|
+{
|
||
|
|
+ f ();
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+test2 (void)
|
||
|
|
+{
|
||
|
|
+ l ();
|
||
|
|
+}
|
||
|
|
diff --git a/gcc/testsuite/gcc.target/loongarch/relocs-symbol-noaddend.c b/gcc/testsuite/gcc.target/loongarch/relocs-symbol-noaddend.c
|
||
|
|
new file mode 100644
|
||
|
|
index 000000000..bfcc9bc33
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/gcc/testsuite/gcc.target/loongarch/relocs-symbol-noaddend.c
|
||
|
|
@@ -0,0 +1,23 @@
|
||
|
|
+/* { dg-do compile } */
|
||
|
|
+/* { dg-options "-mabi=lp64d -mexplicit-relocs -fno-pic -O2" } */
|
||
|
|
+/* { dg-final { scan-assembler "pcalau12i.*%pc_hi20\\(\.LANCHOR0\\)\n" } } */
|
||
|
|
+/* { dg-final { scan-assembler "addi\.d.*%pc_lo12\\(\.LANCHOR0\\)\n" } } */
|
||
|
|
+/* { dg-final { scan-assembler "ldptr.d\t\\\$r4,.*,0\n" } } */
|
||
|
|
+/* { dg-final { scan-assembler "ld.d\t\\\$r5,.*,8\n" } } */
|
||
|
|
+/* { dg-final { scan-assembler-not "\.LANCHOR0+8" } } */
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+struct S
|
||
|
|
+{
|
||
|
|
+ char *a;
|
||
|
|
+ unsigned short int b;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+struct S s1;
|
||
|
|
+
|
||
|
|
+void test(struct S);
|
||
|
|
+void test1(void)
|
||
|
|
+{
|
||
|
|
+ test(s1);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
--
|
||
|
|
2.33.0
|
||
|
|
|