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:
parent
dc76aa0e4d
commit
805a052d00
12 changed files with 402 additions and 37 deletions
|
@ -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);
|
||||
|
|
169
gcc/config/riscv/riscv-zicfilp.cc
Normal file
169
gcc/config/riscv/riscv-zicfilp.cc
Normal 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);
|
||||
}
|
|
@ -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. */
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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 \
|
||||
|
|
7
gcc/testsuite/gcc.target/riscv/interrupt-no-lpad.c
Normal file
7
gcc/testsuite/gcc.target/riscv/interrupt-no-lpad.c
Normal 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" } } */
|
14
gcc/testsuite/gcc.target/riscv/zicfilp-call.c
Normal file
14
gcc/testsuite/gcc.target/riscv/zicfilp-call.c
Normal 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 } } */
|
Loading…
Add table
Reference in a new issue