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 480e6c8856d..4748c0a9a1f 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -143,6 +143,12 @@
   UNSPECV_SSRDP
   UNSPECV_SSP
 
+  ;; ZICFILP
+  UNSPECV_LPAD
+  UNSPECV_SETLPL
+  UNSPECV_LPAD_ALIGN
+  UNSPECV_SET_GUARDED
+
   ;; XTheadInt unspec
   UNSPECV_XTHEADINT_PUSH
   UNSPECV_XTHEADINT_POP
@@ -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

Reply via email to