@@ -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),
@@ -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"
@@ -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);
@@ -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);
new file mode 100644
@@ -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);
+}
@@ -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. */
@@ -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 \
@@ -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")
@@ -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
@@ -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 \
new file mode 100644
@@ -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" } } */
new file mode 100644
@@ -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 } } */