On 10/25/23 19:49, KuanLin Chen wrote:
This is a RFC patch for large code model implementation.
gcc/ChangeLog:
* gcc/config/riscv/predicates.md(move_operand): Check SYMBOL_REF
and LABEL_REF type.
(call_insn_operand): Support for CM_Large.
(pcrel_symbol_operand): New.
* gcc/config/riscv/riscv-c.cc (riscv_cpu_cpp_builtins): Add builtin_define
"__riscv_cmodel_large".
* gcc/config/riscv/riscv-opts.h (riscv_code_model): Define CM_LARGE.
* gcc/config/riscv/riscv-protos.h (riscv_symbol_type): Define
SYMBOL_FORCE_TO_MEM.
(riscv_asm_output_pool_epilogue): New.
* gcc/config/riscv/riscv.cc (riscv_classify_symbol) Support CM_LARGE model.
(riscv_symbol_insns) Add SYMBOL_FORCE_TO_MEM.
(riscv_cannot_force_const_mem): Ditto.
(riscv_split_symbol): Ditto.
(riscv_force_address): Check pseudo reg available before force_reg.
(riscv_size_ok_for_small_data_p): Disable in CM_LARGE model.
(riscv_can_use_per_function_literal_pools_p): New.
(riscv_asm_output_pool_epilogue): New. Hook ASM_OUTPUT_POOL_EPILOGUE.
(riscv_output_mi_thunk): Add riscv_in_thunk_func.
(riscv_option_override): Support CM_LARGE model.
(riscv_function_ok_for_sibcall): Disable sibcalls in CM_LARGE model.
* gcc/config/riscv/riscv.h (ASM_OUTPUT_POOL_EPILOGUE): Hookfg
* gcc/config/riscv/riscv.md (unspec): Define UNSPEC_FORCE_FOR_MEM.
(*large_load_address"): New.
* gcc/config/riscv/riscv.opt (code_model): New.
gcc/testsuite/ChangeLog:
* gcc/testsuite/gcc.target/riscv/large-model.c: New test.
First, thank you so much for tackling this. It's one of the many
missing components that we need to round out the implementation.
0001-RISC-V-Support-mcmodel-large.patch
From b09ba36220db1dbce3b1934685b1783125b5cb66 Mon Sep 17 00:00:00 2001
From: Kuan-Lin Chen<ru...@andestech.com>
Date: Sun, 18 Feb 2018 20:19:49 +0800
Subject: [PATCH] RISC-V: Support -mcmodel=large.
---
gcc/config/riscv/predicates.md | 23 +++++-
gcc/config/riscv/riscv-c.cc | 4 +
gcc/config/riscv/riscv-opts.h | 1 +
gcc/config/riscv/riscv-protos.h | 4 +-
gcc/config/riscv/riscv.cc | 77 +++++++++++++++++++-
gcc/config/riscv/riscv.h | 2 +
gcc/config/riscv/riscv.md | 9 +++
gcc/config/riscv/riscv.opt | 3 +
gcc/testsuite/gcc.target/riscv/large-model.c | 11 +++
9 files changed, 127 insertions(+), 7 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/large-model.c
@@ -312,9 +313,15 @@
})
(define_predicate "call_insn_operand"
- (ior (match_operand 0 "absolute_symbolic_operand")
- (match_operand 0 "plt_symbolic_operand")
- (match_operand 0 "register_operand")))
+ (match_operand 0 "general_operand")
+{
+ if (riscv_cmodel == CM_LARGE)
+ return register_operand (op, mode);
+ else
+ return (absolute_symbolic_operand (op, mode) ||
+ plt_symbolic_operand (op, mode) ||
+ register_operand (op, mode));
+})
Formatting nit. When wrapping a long line, bring the operator down to
the next line, indented just beyond the open paren. Like this:
return (absolute_symbolic_oeprand (op, mode)
|| plt_symbolic_operand (op, mode)
|| register_operand (op, mode);
Also make sure to use a tab when indenting something 8 spaces. It's an
annoyance, but it's the standard way things are formatted in GCC. THere
are some scripts in the contrib subdirectory which can help find
formatting problems, though I'm not sure they work on .md files.
@@ -1972,7 +1992,19 @@ static rtx
riscv_force_address (rtx x, machine_mode mode)
{
if (!riscv_legitimate_address_p (mode, x, false))
- x = force_reg (Pmode, x);
+ {
+ if (can_create_pseudo_p ())
+ return force_reg (Pmode, x);
Note that $ra is fixed now. So if you need a scratch register, you can
fall back to $ra.
More importantly, what are the circumstances where you can be asked to
force an address after the register allocation/reloading phase is
complete? Or does it happen within the register allocators (the latter
would be an indicator we need a secondary reload).
@@ -5665,6 +5697,9 @@ riscv_size_ok_for_small_data_p (int size)
static bool
riscv_in_small_data_p (const_tree x)
{
+ if (riscv_cmodel == CM_LARGE)
+ return false;
+
if (TREE_CODE (x) == STRING_CST || TREE_CODE (x) == FUNCTION_DECL)
return false;
How does large code model impact our ability to access small data
through $gp? Aren't they independent?
+void
+riscv_asm_output_pool_epilogue (FILE *f, const char *, tree,
+ HOST_WIDE_INT offset)
+{
+ /* When using per-function literal pools, we must ensure that any code
+ section is aligned to the minimal instruction length, lest we get
+ errors from the assembler re "unaligned instructions". */
+ if ((offset & 3) && riscv_can_use_per_function_literal_pools_p ())
+ ASM_OUTPUT_ALIGN (f, 2);
+}
So the comment implies you're aligning the section. If that were the
case, then why doesn't the function alignment come from
FUNCTION_BOUNDARY when we first start emitting the function?
Or is it the case that the comment is incorrect and you've actually got
mixed code/rodata?
+(define_insn "*large_load_address"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (mem:DI (match_operand 1 "pcrel_symbol_operand" "")))]
+ "TARGET_64BIT && riscv_cmodel == CM_LARGE"
+ "ld\t%0,%1"
+ [(set_attr "type" "load")
+ (set (attr "length") (const_int 8))])
So it would seem like you're relying on the assembler to expand the ld?
Is there any reasonable way to expose this properly to the compiler?
I'd start by emitting the right instructions in the template. Once
that's working, then we could look to split the components into distinct
insns.
I also worry that we've got a mem->reg move instruction that is not
implemented in the standard movXX patterns. Traditionally that's been a
recipe for problems. It was certainly a requirement for reload, but I
don't know offhand if it's a hard requirement for LRA.
Can you try to merge that in with the standard movdi pattern?
Overall it looks pretty good. Does Andestech have a copyright
assignment in place? Or are you contributing under the DCO rule?
https://gcc.gnu.org/dco.html
JeJeff