This patch only support landing pad value is 0. The next version will implement function signature based labeling scheme.
RISC-V CFI SPEC: https://github.com/riscv/riscv-cfi gcc/ChangeLog: * gcc/common/config/riscv/riscv-common.cc: Add ZICFILP ISA string. * gcc/config.gcc: Add riscv-zicfilp.o * gcc/config/riscv/riscv-passes.def (INSERT_PASS_BEFORE): Insert landing pad instructions. * gcc/config/riscv/riscv-protos.h (make_pass_insert_landing_pad): Declare. * gcc/config/riscv/riscv-zicfilp.cc: New file. * gcc/config/riscv/riscv.cc (riscv_trampoline_init): Add landing pad instructions. (riscv_legitimize_call_address): Likewise. (riscv_output_mi_thunk): Likewise. * gcc/config/riscv/riscv.h: Update. * gcc/config/riscv/riscv.md: Add landing pad patterns. * gcc/config/riscv/riscv.opt (TARGET_ZICFILP): Define. * gcc/config/riscv/t-riscv: Add build rule for riscv-zicfilp.o gcc/testsuite/ChangeLog: * gcc/testsuite/gcc.target/riscv/interrupt-no-lpad.c: New test. * gcc/testsuite/gcc.target/riscv/zicfilp-call.c: New test. Co-Developed-by: Greg McGary <g...@rivosinc.com> Kito Cheng <kito.ch...@gmail.com> --- gcc/common/config/riscv/riscv-common.cc | 3 + gcc/config.gcc | 2 +- gcc/config/riscv/riscv-passes.def | 1 + gcc/config/riscv/riscv-protos.h | 1 + gcc/config/riscv/riscv-zicfilp.cc | 169 ++++++++++++++++++ gcc/config/riscv/riscv.cc | 145 ++++++++++++--- gcc/config/riscv/riscv.h | 13 +- gcc/config/riscv/riscv.md | 73 +++++++- gcc/config/riscv/riscv.opt | 2 + gcc/config/riscv/t-riscv | 9 + .../gcc.target/riscv/interrupt-no-lpad.c | 7 + gcc/testsuite/gcc.target/riscv/zicfilp-call.c | 14 ++ 12 files changed, 402 insertions(+), 37 deletions(-) create mode 100644 gcc/config/riscv/riscv-zicfilp.cc create mode 100644 gcc/testsuite/gcc.target/riscv/interrupt-no-lpad.c create mode 100644 gcc/testsuite/gcc.target/riscv/zicfilp-call.c diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc index 8e8b6107a6d..5038f0eb959 100644 --- a/gcc/common/config/riscv/riscv-common.cc +++ b/gcc/common/config/riscv/riscv-common.cc @@ -113,6 +113,7 @@ static const riscv_implied_info_t riscv_implied_info[] = {"zicfiss", "zicsr"}, {"zicfiss", "zimop"}, + {"zicfilp", "zicsr"}, {"zk", "zkn"}, {"zk", "zkr"}, @@ -329,6 +330,7 @@ static const struct riscv_ext_version riscv_ext_version_table[] = {"ziccrse", ISA_SPEC_CLASS_NONE, 1, 0}, {"zicfiss", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zicfilp", ISA_SPEC_CLASS_NONE, 1, 0}, {"zimop", ISA_SPEC_CLASS_NONE, 1, 0}, {"zcmop", ISA_SPEC_CLASS_NONE, 1, 0}, @@ -1653,6 +1655,7 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] = RISCV_EXT_FLAG_ENTRY ("zic64b", x_riscv_zicmo_subext, MASK_ZIC64B), RISCV_EXT_FLAG_ENTRY ("zicfiss", x_riscv_zi_subext, MASK_ZICFISS), + RISCV_EXT_FLAG_ENTRY ("zicfilp", x_riscv_zi_subext, MASK_ZICFILP), RISCV_EXT_FLAG_ENTRY ("zimop", x_riscv_mop_subext, MASK_ZIMOP), RISCV_EXT_FLAG_ENTRY ("zcmop", x_riscv_mop_subext, MASK_ZCMOP), diff --git a/gcc/config.gcc b/gcc/config.gcc index 55e37146ee0..87fed823118 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -553,7 +553,7 @@ riscv*) extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o riscv-string.o" extra_objs="${extra_objs} riscv-v.o riscv-vsetvl.o riscv-vector-costs.o riscv-avlprop.o" extra_objs="${extra_objs} riscv-vector-builtins.o riscv-vector-builtins-shapes.o riscv-vector-builtins-bases.o sifive-vector-builtins-bases.o" - extra_objs="${extra_objs} thead.o riscv-target-attr.o" + extra_objs="${extra_objs} thead.o riscv-target-attr.o riscv-zicfilp.o" d_target_objs="riscv-d.o" extra_headers="riscv_vector.h riscv_crypto.h riscv_bitmanip.h riscv_th_vector.h riscv_cmo.h" target_gtfiles="$target_gtfiles \$(srcdir)/config/riscv/riscv-vector-builtins.cc" diff --git a/gcc/config/riscv/riscv-passes.def b/gcc/config/riscv/riscv-passes.def index cbea23c8b44..7e6a2a0e53d 100644 --- a/gcc/config/riscv/riscv-passes.def +++ b/gcc/config/riscv/riscv-passes.def @@ -20,3 +20,4 @@ INSERT_PASS_AFTER (pass_rtl_store_motion, 1, pass_shorten_memrefs); INSERT_PASS_AFTER (pass_split_all_insns, 1, pass_avlprop); INSERT_PASS_BEFORE (pass_fast_rtl_dce, 1, pass_vsetvl); +INSERT_PASS_BEFORE (pass_shorten_branches, 1, pass_insert_landing_pad); diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index dd3b36d47a6..6362380ec6c 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -200,6 +200,7 @@ extern bool riscv_hard_regno_rename_ok (unsigned, unsigned); rtl_opt_pass * make_pass_shorten_memrefs (gcc::context *ctxt); rtl_opt_pass * make_pass_avlprop (gcc::context *ctxt); rtl_opt_pass * make_pass_vsetvl (gcc::context *ctxt); +rtl_opt_pass * make_pass_insert_landing_pad (gcc::context *ctxt); /* Routines implemented in riscv-string.c. */ extern bool riscv_expand_block_compare (rtx, rtx, rtx, rtx); diff --git a/gcc/config/riscv/riscv-zicfilp.cc b/gcc/config/riscv/riscv-zicfilp.cc new file mode 100644 index 00000000000..42b129920b3 --- /dev/null +++ b/gcc/config/riscv/riscv-zicfilp.cc @@ -0,0 +1,169 @@ +/* Branch Target Identification for RISCV architecture. + Copyright (C) 2019-2025 Free Software Foundation, Inc. + Based on ARM target. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +#define IN_TARGET_CODE 1 + +#include "config.h" +#define INCLUDE_STRING +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "target.h" +#include "rtl.h" +#include "tree.h" +#include "memmodel.h" +#include "gimple.h" +#include "tm_p.h" +#include "stringpool.h" +#include "attribs.h" +#include "expr.h" +#include "emit-rtl.h" +#include "gimplify.h" +#include "gimple-iterator.h" +#include "dumpfile.h" +#include "rtl-iter.h" +#include "cfgrtl.h" +#include "tree-pass.h" +#include "cgraph.h" +#include "output.h" + +/* This pass implements forward-CFI landing pad checks for RISCV. This is + a security feature similar to BTI (branch target identification) in + AArch64 and IBT (indirect branch tracking)in X86. A LPAD (landing-pad + check) instruction is used to guard against the execution of + instructions which are not the intended target of an indirect branch. + + When forward-CFI is disabled or unimplemented in the CPU, the + landing-pad check label instructions behave as NOP. When implemented in + the CPU, and enabled, the destination of an indirect branch must be + LPAD insn. Otherwise, the CPU reaises an exception. + + In order to enable this mechanism, this pass iterates through the + control flow of the code and adds appropriate LPAD instructions at the + beginning of any function that can be called indirectly, and for targets + of indirect jumps, i.e., jump table targets, non-local goto targets, and + labels that might be referenced by variables, constant pools, etc + (NOTE_INSN_DELETED_LABEL). */ + +namespace { + +const pass_data pass_data_insert_landing_pad = +{ + RTL_PASS, /* type. */ + "zisslpcfi", /* name. */ + OPTGROUP_NONE, /* optinfo_flags. */ + TV_MACH_DEP, /* tv_id. */ + 0, /* properties_required. */ + 0, /* properties_provided. */ + 0, /* properties_destroyed. */ + 0, /* todo_flags_start. */ + 0, /* todo_flags_finish. */ +}; + +static bool +is_interrupt_handler_p (tree type) +{ + return lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type)) != NULL; +} + +/* Insert landing-pad check instructions. This is a late RTL pass that runs + before branch shortening. */ +static unsigned int +rest_of_insert_landing_pad (void) +{ + timevar_push (TV_MACH_DEP); + + struct cgraph_node *c_node; + rtx lpad_insn; + rtx_insn *insn; + basic_block bb; + + bb = 0; + FOR_EACH_BB_FN (bb, cfun) + { + for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb)); + insn = NEXT_INSN (insn)) + { + /* If a label is marked to be preserved or can be a non-local goto + target, it must be protected with a lpad instruction. */ + if (LABEL_P (insn) + && (LABEL_PRESERVE_P (insn) + || bb->flags & BB_NON_LOCAL_GOTO_TARGET)) + { + emit_insn_before (gen_lpad_align (), insn); + emit_insn_after (gen_lpad (const0_rtx), insn); + continue; + } + + if (INSN_P (insn) && INSN_CODE (insn) == CODE_FOR_gpr_save) + { + emit_move_insn (RISCV_CALL_ADDRESS_LPAD (Pmode), const0_rtx); + emit_insn_before (gen_lpad_align (), insn); + emit_insn_after (gen_lpad (const0_rtx), insn); + continue; + } + + if (INSN_P (insn) && INSN_CODE (insn) == CODE_FOR_gpr_restore) + emit_move_insn (RISCV_CALL_ADDRESS_LPAD (Pmode), const0_rtx); + + } + } + + c_node = cgraph_node::get (cfun->decl); + if (!c_node->only_called_directly_p () + && !is_interrupt_handler_p (TREE_TYPE (cfun->decl))) + { + bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb; + insn = BB_HEAD (bb); + lpad_insn = gen_lpad (const0_rtx); + emit_insn_before (lpad_insn, insn); + } + + timevar_pop (TV_MACH_DEP); + return 0; +} + +class pass_insert_landing_pad : public rtl_opt_pass +{ +public: + pass_insert_landing_pad (gcc::context *ctxt) + : rtl_opt_pass (pass_data_insert_landing_pad, ctxt) + {} + + /* opt_pass methods: */ + virtual bool gate (function *) + { + return TARGET_ZICFILP; + } + + virtual unsigned int execute (function *) + { + return rest_of_insert_landing_pad (); + } + +}; // class pass_insert_landing_pad + +} // anon namespace + +rtl_opt_pass * +make_pass_insert_landing_pad (gcc::context *ctxt) +{ + return new pass_insert_landing_pad (ctxt); +} diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index cd37b492183..4afb0b95839 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -6681,8 +6681,20 @@ riscv_legitimize_call_address (rtx addr) { rtx reg = RISCV_CALL_ADDRESS_TEMP (Pmode); riscv_emit_move (reg, addr); + + if (TARGET_ZICFILP) + { + rtx sw_guarded = RISCV_CALL_ADDRESS_LPAD (Pmode); + emit_insn (gen_set_guarded (Pmode, reg)); + return sw_guarded; + } + return reg; } + + if (TARGET_ZICFILP && REG_P (addr)) + emit_insn (gen_set_lpl (Pmode, const0_rtx)); + return addr; } @@ -10342,6 +10354,9 @@ riscv_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, /* Mark the end of the (empty) prologue. */ emit_note (NOTE_INSN_PROLOGUE_END); + if (TARGET_ZICFILP) + emit_insn(gen_lpad (const0_rtx)); + /* Determine if we can use a sibcall to call FUNCTION directly. */ fnaddr = gen_rtx_MEM (FUNCTION_MODE, XEXP (DECL_RTL (function), 0)); @@ -10853,12 +10868,17 @@ riscv_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) { rtx addr, end_addr, mem; uint32_t trampoline[4]; + uint32_t trampoline_cfi[6]; unsigned int i; HOST_WIDE_INT static_chain_offset, target_function_offset; + HOST_WIDE_INT lp_value = 0; /* Work out the offsets of the pointers from the start of the trampoline code. */ - gcc_assert (ARRAY_SIZE (trampoline) * 4 == TRAMPOLINE_CODE_SIZE); + if (!TARGET_ZICFILP) + gcc_assert (ARRAY_SIZE (trampoline) * 4 == TRAMPOLINE_CODE_SIZE); + else + gcc_assert (ARRAY_SIZE (trampoline_cfi) * 4 == TRAMPOLINE_CODE_SIZE); /* Get pointers to the beginning and end of the code block. */ addr = force_reg (Pmode, XEXP (m_tramp, 0)); @@ -10880,6 +10900,17 @@ riscv_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) unsigned HOST_WIDE_INT lo_chain_code, lo_func_code; rtx uimm_mask = force_reg (SImode, gen_int_mode (-IMM_REACH, SImode)); + unsigned insn_count = 0; + + /* Insert lpad, if zicfilp is enabled. */ + if (TARGET_ZICFILP) + { + unsigned HOST_WIDE_INT lpad_code; + lpad_code = OPCODE_AUIPC | (0 << SHIFT_RD) | (lp_value << IMM_BITS); + mem = adjust_address (m_tramp, SImode, 0); + riscv_emit_move (mem, gen_int_mode (lpad_code, SImode)); + insn_count++; + } /* 0xfff. */ rtx imm12_mask = gen_reg_rtx (SImode); @@ -10893,11 +10924,14 @@ riscv_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) hi_chain = riscv_force_binary (SImode, AND, hi_chain, uimm_mask); lui_hi_chain_code = OPCODE_LUI | (STATIC_CHAIN_REGNUM << SHIFT_RD); + rtx lui_hi_chain_value = force_reg (SImode, gen_int_mode (lui_hi_chain_code, + SImode)); rtx lui_hi_chain = riscv_force_binary (SImode, IOR, hi_chain, - gen_int_mode (lui_hi_chain_code, SImode)); - - mem = adjust_address (m_tramp, SImode, 0); + lui_hi_chain_value); + mem = adjust_address (m_tramp, SImode, + insn_count * GET_MODE_SIZE (SImode)); riscv_emit_move (mem, riscv_swap_instruction (lui_hi_chain)); + insn_count++; /* Gen lui t0, hi(func). */ rtx hi_func = riscv_force_binary (SImode, PLUS, target_function, @@ -10908,8 +10942,10 @@ riscv_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) rtx lui_hi_func = riscv_force_binary (SImode, IOR, hi_func, gen_int_mode (lui_hi_func_code, SImode)); - mem = adjust_address (m_tramp, SImode, 1 * GET_MODE_SIZE (SImode)); + mem = adjust_address (m_tramp, SImode, + insn_count * GET_MODE_SIZE (SImode)); riscv_emit_move (mem, riscv_swap_instruction (lui_hi_func)); + insn_count++; /* Gen addi t2, t2, lo(chain). */ rtx lo_chain = riscv_force_binary (SImode, AND, chain_value, @@ -10923,8 +10959,23 @@ riscv_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) rtx addi_lo_chain = riscv_force_binary (SImode, IOR, lo_chain, force_reg (SImode, GEN_INT (lo_chain_code))); - mem = adjust_address (m_tramp, SImode, 2 * GET_MODE_SIZE (SImode)); + mem = adjust_address (m_tramp, SImode, + insn_count * GET_MODE_SIZE (SImode)); riscv_emit_move (mem, riscv_swap_instruction (addi_lo_chain)); + insn_count++; + + /* For zicfilp only, insert lui t2, 1, because use jr t0. */ + if (TARGET_ZICFILP) + { + unsigned HOST_WIDE_INT set_lpl_code; + set_lpl_code = OPCODE_LUI + | (RISCV_CALL_ADDRESS_LPAD_REGNUM << SHIFT_RD) + | (lp_value << IMM_BITS); + mem = adjust_address (m_tramp, SImode, + insn_count * GET_MODE_SIZE (SImode)); + riscv_emit_move (mem, gen_int_mode (set_lpl_code, SImode)); + insn_count++; + } /* Gen jr t0, lo(func). */ rtx lo_func = riscv_force_binary (SImode, AND, target_function, @@ -10936,7 +10987,7 @@ riscv_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) rtx jr_lo_func = riscv_force_binary (SImode, IOR, lo_func, force_reg (SImode, GEN_INT (lo_func_code))); - mem = adjust_address (m_tramp, SImode, 3 * GET_MODE_SIZE (SImode)); + mem = adjust_address (m_tramp, SImode, insn_count * GET_MODE_SIZE (SImode)); riscv_emit_move (mem, riscv_swap_instruction (jr_lo_func)); } else @@ -10944,29 +10995,65 @@ riscv_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) static_chain_offset = TRAMPOLINE_CODE_SIZE; target_function_offset = static_chain_offset + GET_MODE_SIZE (ptr_mode); - /* auipc t2, 0 - l[wd] t0, target_function_offset(t2) - l[wd] t2, static_chain_offset(t2) - jr t0 - */ - trampoline[0] = OPCODE_AUIPC | (STATIC_CHAIN_REGNUM << SHIFT_RD); - trampoline[1] = (Pmode == DImode ? OPCODE_LD : OPCODE_LW) - | (RISCV_PROLOGUE_TEMP_REGNUM << SHIFT_RD) - | (STATIC_CHAIN_REGNUM << SHIFT_RS1) - | (target_function_offset << SHIFT_IMM); - trampoline[2] = (Pmode == DImode ? OPCODE_LD : OPCODE_LW) - | (STATIC_CHAIN_REGNUM << SHIFT_RD) - | (STATIC_CHAIN_REGNUM << SHIFT_RS1) - | (static_chain_offset << SHIFT_IMM); - trampoline[3] = OPCODE_JALR | (RISCV_PROLOGUE_TEMP_REGNUM << SHIFT_RS1); - - /* Copy the trampoline code. */ - for (i = 0; i < ARRAY_SIZE (trampoline); i++) + if (!TARGET_ZICFILP) { - if (BYTES_BIG_ENDIAN) - trampoline[i] = __builtin_bswap32(trampoline[i]); - mem = adjust_address (m_tramp, SImode, i * GET_MODE_SIZE (SImode)); - riscv_emit_move (mem, gen_int_mode (trampoline[i], SImode)); + /* auipc t2, 0 + l[wd] t0, (target_function_offset)(t2) + l[wd] t2, (static_chain_offset)(t2) + jr t0 + */ + trampoline[0] = OPCODE_AUIPC | (STATIC_CHAIN_REGNUM << SHIFT_RD); + trampoline[1] = (Pmode == DImode ? OPCODE_LD : OPCODE_LW) + | (RISCV_PROLOGUE_TEMP_REGNUM << SHIFT_RD) + | (STATIC_CHAIN_REGNUM << SHIFT_RS1) + | (target_function_offset << SHIFT_IMM); + trampoline[2] = (Pmode == DImode ? OPCODE_LD : OPCODE_LW) + | (STATIC_CHAIN_REGNUM << SHIFT_RD) + | (STATIC_CHAIN_REGNUM << SHIFT_RS1) + | (static_chain_offset << SHIFT_IMM); + trampoline[3] = OPCODE_JALR | (RISCV_PROLOGUE_TEMP_REGNUM << SHIFT_RS1); + + /* Copy the trampoline code. */ + for (i = 0; i < ARRAY_SIZE (trampoline); i++) + { + if (BYTES_BIG_ENDIAN) + trampoline[i] = __builtin_bswap32 (trampoline[i]); + mem = adjust_address (m_tramp, SImode, i * GET_MODE_SIZE (SImode)); + riscv_emit_move (mem, gen_int_mode (trampoline[i], SImode)); + } + } + else + { + /* lpad 1 + auipc t3, 0 + l[wd] t0, (target_function_offset - 4)(t3) + l[wd] t3, (static_chain_offset - 4)(t3) + lui t2, 1 + jr t0 + */ + trampoline_cfi[0] = OPCODE_AUIPC | (0 << SHIFT_RD) | (lp_value << IMM_BITS); + trampoline_cfi[1] = OPCODE_AUIPC | (STATIC_CHAIN_REGNUM << SHIFT_RD); + trampoline_cfi[2] = (Pmode == DImode ? OPCODE_LD : OPCODE_LW) + | (RISCV_PROLOGUE_TEMP_REGNUM << SHIFT_RD) + | (STATIC_CHAIN_REGNUM << SHIFT_RS1) + | ((target_function_offset - 4) << SHIFT_IMM); + trampoline_cfi[3] = (Pmode == DImode ? OPCODE_LD : OPCODE_LW) + | (STATIC_CHAIN_REGNUM << SHIFT_RD) + | (STATIC_CHAIN_REGNUM << SHIFT_RS1) + | ((static_chain_offset - 4) << SHIFT_IMM); + trampoline_cfi[4] = OPCODE_LUI + | (RISCV_CALL_ADDRESS_LPAD_REGNUM << SHIFT_RD) + | (lp_value << IMM_BITS); + trampoline_cfi[5] = OPCODE_JALR | (RISCV_PROLOGUE_TEMP_REGNUM << SHIFT_RS1); + + /* Copy the trampoline code. */ + for (i = 0; i < ARRAY_SIZE (trampoline_cfi); i++) + { + if (BYTES_BIG_ENDIAN) + trampoline_cfi[i] = __builtin_bswap32 (trampoline_cfi[i]); + mem = adjust_address (m_tramp, SImode, i * GET_MODE_SIZE (SImode)); + riscv_emit_move (mem, gen_int_mode (trampoline_cfi[i], SImode)); + } } /* Set up the static chain pointer field. */ diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h index 93e88fe885d..073b9e4f2bd 100644 --- a/gcc/config/riscv/riscv.h +++ b/gcc/config/riscv/riscv.h @@ -190,7 +190,8 @@ ASM_MISA_SPEC #define PARM_BOUNDARY BITS_PER_WORD /* Allocation boundary (in *bits*) for the code of a function. */ -#define FUNCTION_BOUNDARY ((TARGET_RVC || TARGET_ZCA) ? 16 : 32) +#define FUNCTION_BOUNDARY \ + (((TARGET_RVC || TARGET_ZCA) && !TARGET_ZICFILP) ? 16 : 32) /* The smallest supported stack boundary the calling convention supports. */ #define STACK_BOUNDARY \ @@ -413,7 +414,8 @@ ASM_MISA_SPEC #define RISCV_DWARF_VLENB (4096 + 0xc22) /* Register in which static-chain is passed to a function. */ -#define STATIC_CHAIN_REGNUM (GP_TEMP_FIRST + 2) +#define STATIC_CHAIN_REGNUM \ + ((TARGET_ZICFILP) ? (GP_TEMP_FIRST + 23) : (GP_TEMP_FIRST + 2)) /* Registers used as temporaries in prologue/epilogue code. @@ -436,6 +438,10 @@ ASM_MISA_SPEC #define RISCV_CALL_ADDRESS_TEMP(MODE) \ gen_rtx_REG (MODE, RISCV_CALL_ADDRESS_TEMP_REGNUM) +#define RISCV_CALL_ADDRESS_LPAD_REGNUM (GP_TEMP_FIRST + 2) +#define RISCV_CALL_ADDRESS_LPAD(MODE) \ + gen_rtx_REG (MODE, RISCV_CALL_ADDRESS_LPAD_REGNUM) + #define RETURN_ADDR_MASK (1 << RETURN_ADDR_REGNUM) #define S0_MASK (1 << S0_REGNUM) #define S1_MASK (1 << S1_REGNUM) @@ -821,7 +827,8 @@ extern enum riscv_cc get_riscv_cc (const rtx use); /* Trampolines are a block of code followed by two pointers. */ -#define TRAMPOLINE_CODE_SIZE 16 +#define TRAMPOLINE_CODE_SIZE ((TARGET_ZICFILP) ? 24 : 16) + #define TRAMPOLINE_SIZE \ ((Pmode == SImode) \ ? TRAMPOLINE_CODE_SIZE \ diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index 21094395184..5b4c81bb9e0 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -105,6 +105,12 @@ UNSPECV_SSPOPCHK UNSPECV_SSRDP UNSPECV_SSP + + ;; ZICFILP + UNSPECV_LPAD + UNSPECV_SETLPL + UNSPECV_LPAD_ALIGN + UNSPECV_SET_GUARDED ]) (define_c_enum "unspecv" [ @@ -155,6 +161,7 @@ (TP_REGNUM 4) (T0_REGNUM 5) (T1_REGNUM 6) + (T2_REGNUM 7) (S0_REGNUM 8) (S1_REGNUM 9) (A0_REGNUM 10) @@ -3709,11 +3716,18 @@ [(set (pc) (match_operand 0 "register_operand"))] "" { + if (TARGET_ZICFILP) + emit_insn (gen_set_lpl (Pmode, const0_rtx)); + operands[0] = force_reg (Pmode, operands[0]); + if (TARGET_ZICFILP) + emit_use (gen_rtx_REG (Pmode, T2_REGNUM)); + if (Pmode == SImode) emit_jump_insn (gen_indirect_jumpsi (operands[0])); else emit_jump_insn (gen_indirect_jumpdi (operands[0])); + DONE; }) @@ -3734,21 +3748,42 @@ gen_rtx_LABEL_REF (Pmode, operands[1]), NULL_RTX, 0, OPTAB_DIRECT); - if (CASE_VECTOR_PC_RELATIVE && Pmode == DImode) - emit_jump_insn (gen_tablejumpdi (operands[0], operands[1])); + if (TARGET_ZICFILP) + { + rtx t2 = RISCV_CALL_ADDRESS_LPAD (GET_MODE (operands[0])); + emit_move_insn (t2, operands[0]); + + if (CASE_VECTOR_PC_RELATIVE && Pmode == DImode) + emit_jump_insn (gen_tablejump_cfidi (operands[1])); + else + emit_jump_insn (gen_tablejump_cfisi (operands[1])); + } else - emit_jump_insn (gen_tablejumpsi (operands[0], operands[1])); + { + if (CASE_VECTOR_PC_RELATIVE && Pmode == DImode) + emit_jump_insn (gen_tablejumpdi (operands[0], operands[1])); + else + emit_jump_insn (gen_tablejumpsi (operands[0], operands[1])); + } DONE; }) (define_insn "tablejump<mode>" [(set (pc) (match_operand:GPR 0 "register_operand" "l")) (use (label_ref (match_operand 1 "" "")))] - "" + "!TARGET_ZICFILP" "jr\t%0" [(set_attr "type" "jalr") (set_attr "mode" "none")]) +(define_insn "tablejump_cfi<mode>" + [(set (pc) (reg:GPR T2_REGNUM)) + (use (label_ref (match_operand 0 "")))] + "TARGET_ZICFILP" + "jr\tt2" + [(set_attr "type" "jalr") + (set_attr "mode" "none")]) + ;; ;; .................... ;; @@ -4718,6 +4753,36 @@ [(set_attr "type" "arith") (set_attr "mode" "<MODE>")]) +;; Lading pad. + +(define_insn "lpad" + [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] UNSPECV_LPAD)] + "TARGET_ZICFILP" + "lpad\t%0" + [(set_attr "type" "auipc")]) + +(define_insn "@set_lpl<mode>" + [(set (reg:GPR T2_REGNUM) + (unspec_volatile [(match_operand:GPR 0 "immediate_operand" "i")] UNSPECV_SETLPL))] + "TARGET_ZICFILP" + "lui\tt2,%0" + [(set_attr "type" "const") + (set_attr "mode" "<MODE>")]) + +(define_insn "lpad_align" + [(unspec_volatile [(const_int 0)] UNSPECV_LPAD_ALIGN)] + "TARGET_ZICFILP" + ".align 2" + [(set_attr "type" "nop")]) + +(define_insn "@set_guarded<mode>" + [(set (reg:GPR T2_REGNUM) + (unspec_volatile [(match_operand:GPR 0 "register_operand" "r")] UNSPECV_SET_GUARDED))] + "TARGET_ZICFILP" + "mv\tt2,%0" + [(set_attr "type" "move") + (set_attr "mode" "<MODE>")]) + (include "bitmanip.md") (include "crypto.md") (include "sync.md") diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt index 4a43bfd7bc6..f51f8fd1cdf 100644 --- a/gcc/config/riscv/riscv.opt +++ b/gcc/config/riscv/riscv.opt @@ -255,6 +255,8 @@ Mask(ZICCRSE) Var(riscv_zi_subext) Mask(ZICFISS) Var(riscv_zi_subext) +Mask(ZICFILP) Var(riscv_zi_subext) + TargetVariable int riscv_za_subext diff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv index bc67d8719fa..6493087fe51 100644 --- a/gcc/config/riscv/t-riscv +++ b/gcc/config/riscv/t-riscv @@ -145,6 +145,15 @@ thead.o: $(srcdir)/config/riscv/thead.cc \ $(COMPILE) $< $(POSTCOMPILE) +riscv-zicfilp.o: $(srcdir)/config/riscv/riscv-zicfilp.cc \ + $(CONFIG_H) $(SYSTEM_H) $(TM_H) $(REGS_H) insn-config.h $(RTL_BASE_H) \ + dominance.h cfg.h cfganal.h $(BASIC_BLOCK_H) $(INSN_ATTR_H) $(RECOG_H) \ + output.h hash-map.h $(DF_H) $(OBSTACK_H) $(TARGET_H) $(RTL_H) \ + $(CONTEXT_H) $(TREE_PASS_H) regrename.h \ + $(srcdir)/config/riscv/riscv-protos.h + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/riscv/riscv-zicfilp.cc + PASSES_EXTRA += $(srcdir)/config/riscv/riscv-passes.def $(common_out_file): $(srcdir)/config/riscv/riscv-cores.def \ diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-no-lpad.c b/gcc/testsuite/gcc.target/riscv/interrupt-no-lpad.c new file mode 100644 index 00000000000..ff512b98c61 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/interrupt-no-lpad.c @@ -0,0 +1,7 @@ +/* { dg-do compile { target { riscv64*-*-* } } } */ +/* { dg-options "-march=rv64gc_zicfilp -mabi=lp64d" } */ +void __attribute__ ((interrupt)) +foo (void) +{ +} +/* { dg-final { scan-assembler-not "lpad\t" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zicfilp-call.c b/gcc/testsuite/gcc.target/riscv/zicfilp-call.c new file mode 100644 index 00000000000..75c8b32faa3 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zicfilp-call.c @@ -0,0 +1,14 @@ +/* { dg-do compile { target { riscv64*-*-* } } } */ +/* { dg-options "-O2 -fPIE -march=rv64gc_zicfilp -mabi=lp64d" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } } */ + +extern void _dl_find_object_init (void); + +void +_dl_non_dynamic_init (void) +{ + extern __typeof__ (_dl_find_object_init) _dl_find_object_init __attribute__ ((weak)); + (_dl_find_object_init != ((void *) 0) ? _dl_find_object_init () : (void)0); +} + +/* { dg-final { scan-assembler-times "mv\tt2" 1 } } */ -- 2.47.1