RISC-V: Add Zicfilp ISA extension.

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:
	* common/config/riscv/riscv-common.cc: Add ZICFILP ISA
	string.
	* config.gcc: Add riscv-zicfilp.o
	* config/riscv/riscv-passes.def (INSERT_PASS_BEFORE):
	Insert landing pad instructions.
	* config/riscv/riscv-protos.h (make_pass_insert_landing_pad):
	Declare.
	* config/riscv/riscv-zicfilp.cc: New file.
	* config/riscv/riscv.cc
	(riscv_trampoline_init): Add landing pad instructions.
	(riscv_legitimize_call_address): Likewise.
	(riscv_output_mi_thunk): Likewise.
	* config/riscv/riscv.h: Update.
	* config/riscv/riscv.md: Add landing pad patterns.
	* config/riscv/riscv.opt (TARGET_ZICFILP): Define.
	* config/riscv/t-riscv: Add build rule for
	riscv-zicfilp.o

gcc/testsuite/ChangeLog:
	* gcc.target/riscv/interrupt-no-lpad.c: New test.
	* gcc.target/riscv/zicfilp-call.c: New test.

	Co-Developed-by: Greg McGary <gkm@rivosinc.com>,
			Kito Cheng <kito.cheng@gmail.com>
This commit is contained in:
Monk Chiang 2024-03-22 21:00:24 +08:00
parent dc76aa0e4d
commit 805a052d00
12 changed files with 402 additions and 37 deletions

View file

@ -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),

View file

@ -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"

View file

@ -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);

View file

@ -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);

View file

@ -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);
}

View file

@ -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;
}
@ -10341,6 +10353,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));
@ -10852,12 +10867,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));
@ -10879,6 +10899,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);
@ -10892,11 +10923,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,
@ -10907,8 +10941,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,
@ -10922,8 +10958,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,
@ -10935,7 +10986,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
@ -10943,29 +10994,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. */

View file

@ -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 \

View file

@ -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)
@ -3704,11 +3711,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;
})
@ -3729,21 +3743,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")])
;;
;; ....................
;;
@ -4713,6 +4748,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")

View file

@ -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

View file

@ -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 \

View file

@ -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" } } */

View file

@ -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 } } */