This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH, i386, Pointer Bounds Checker 32/x] Pointer Bounds Checker hooks for i386 target
- From: Ilya Enkovich <enkovich dot gnu at gmail dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 11 Jun 2014 18:00:55 +0400
- Subject: [PATCH, i386, Pointer Bounds Checker 32/x] Pointer Bounds Checker hooks for i386 target
- Authentication-results: sourceware.org; auth=none
Hi,
This patch adds i386 target hooks for Pointer Bounds Checker.
Bootstrapped and tested on linux-x86_64.
Thanks,
Ilya
--
gcc/
2014-06-11 Ilya Enkovich <ilya.enkovich@intel.com>
* config/i386/i386.c: Include tree-iterator.h.
(ix86_function_value_bounds): New.
(ix86_builtin_mpx_function): New.
(ix86_load_bounds): New.
(ix86_store_bounds): New.
(ix86_load_returned_bounds): New.
(ix86_store_returned_bounds): New.
(ix86_fn_abi_va_list_bounds_size): New.
(ix86_mpx_bound_mode): New.
(ix86_make_bounds_constant): New.
(ix86_initialize_bounds):
(TARGET_LOAD_BOUNDS_FOR_ARG): New.
(TARGET_STORE_BOUNDS_FOR_ARG): New.
(TARGET_LOAD_RETURNED_BOUNDS): New.
(TARGET_STORE_RETURNED_BOUNDS): New.
(TARGET_CHKP_BOUND_MODE): New.
(TARGET_BUILTIN_CHKP_FUNCTION): New.
(TARGET_FN_ABI_VA_LIST_BOUNDS_SIZE): New.
(TARGET_CHKP_FUNCTION_VALUE_BOUNDS): New.
(TARGET_CHKP_MAKE_BOUNDS_CONSTANT): New.
(TARGET_CHKP_INITIALIZE_BOUNDS): New.
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index ac79231..dac83d0 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -81,6 +81,7 @@ along with GCC; see the file COPYING3. If not see
#include "context.h"
#include "pass_manager.h"
#include "target-globals.h"
+#include "tree-iterator.h"
#include "tree-chkp.h"
#include "rtl-chkp.h"
@@ -7971,6 +7972,39 @@ ix86_function_value (const_tree valtype, const_tree fntype_or_decl,
return ix86_function_value_1 (valtype, fntype_or_decl, orig_mode, mode);
}
+static rtx
+ix86_function_value_bounds (const_tree valtype,
+ const_tree fntype_or_decl ATTRIBUTE_UNUSED,
+ bool outgoing ATTRIBUTE_UNUSED)
+{
+ rtx res = NULL_RTX;
+
+ if (BOUNDED_TYPE_P (valtype))
+ res = gen_rtx_REG (BNDmode, FIRST_BND_REG);
+ else if (chkp_type_has_pointer (valtype))
+ {
+ bitmap slots = chkp_find_bound_slots (valtype);
+ rtx bounds[2];
+ bitmap_iterator bi;
+ unsigned i, bnd_no = 0;
+
+ EXECUTE_IF_SET_IN_BITMAP (slots, 0, i, bi)
+ {
+ rtx reg = gen_rtx_REG (BNDmode, FIRST_BND_REG + bnd_no);
+ rtx offs = GEN_INT (i * POINTER_SIZE / BITS_PER_UNIT);
+ gcc_assert (bnd_no < 2);
+ bounds[bnd_no++] = gen_rtx_EXPR_LIST (VOIDmode, reg, offs);
+ }
+
+ res = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (bnd_no, bounds));
+ BITMAP_FREE (slots);
+ }
+ else
+ res = NULL_RTX;
+
+ return res;
+}
+
/* Pointer function arguments and return values are promoted to
word_mode. */
@@ -36620,6 +36654,173 @@ static tree ix86_get_builtin (enum ix86_builtins code)
return NULL_TREE;
}
+/* Return function decl for target specific builtin
+ for given MPX builtin passed i FCODE. */
+static tree
+ix86_builtin_mpx_function (unsigned fcode)
+{
+ switch (fcode)
+ {
+ case BUILT_IN_CHKP_BNDMK:
+ return ix86_builtins[IX86_BUILTIN_BNDMK];
+
+ case BUILT_IN_CHKP_BNDSTX:
+ return ix86_builtins[IX86_BUILTIN_BNDSTX];
+
+ case BUILT_IN_CHKP_BNDLDX:
+ return ix86_builtins[IX86_BUILTIN_BNDLDX];
+
+ case BUILT_IN_CHKP_BNDCL:
+ return ix86_builtins[IX86_BUILTIN_BNDCL];
+
+ case BUILT_IN_CHKP_BNDCU:
+ return ix86_builtins[IX86_BUILTIN_BNDCU];
+
+ case BUILT_IN_CHKP_BNDRET:
+ return ix86_builtins[IX86_BUILTIN_BNDRET];
+
+ case BUILT_IN_CHKP_INTERSECT:
+ return ix86_builtins[IX86_BUILTIN_BNDINT];
+
+ case BUILT_IN_CHKP_NARROW:
+ return ix86_builtins[IX86_BUILTIN_BNDNARROW];
+
+ case BUILT_IN_CHKP_SIZEOF:
+ return ix86_builtins[IX86_BUILTIN_SIZEOF];
+
+ case BUILT_IN_CHKP_EXTRACT_LOWER:
+ return ix86_builtins[IX86_BUILTIN_BNDLOWER];
+
+ case BUILT_IN_CHKP_EXTRACT_UPPER:
+ return ix86_builtins[IX86_BUILTIN_BNDUPPER];
+
+ default:
+ return NULL_TREE;
+ }
+
+ gcc_unreachable ();
+}
+
+/* Load bounds PTR pointer value loaded from SLOT.
+ if SLOT is a register then load bounds associated
+ with special address identified by BND.
+
+ Return loaded bounds. */
+static rtx
+ix86_load_bounds (rtx slot, rtx ptr, rtx bnd)
+{
+ rtx addr = NULL;
+ rtx reg;
+
+ if (!ptr)
+ {
+ gcc_assert (MEM_P (slot));
+ ptr = copy_to_mode_reg (Pmode, slot);
+ }
+
+ if (!slot || REG_P (slot))
+ {
+ if (slot)
+ ptr = slot;
+
+ gcc_assert (CONST_INT_P (bnd));
+
+ /* Here we have the case when more than four pointers are
+ passed in registers. In this case we are out of bound
+ registers and have to use bndldx to load bound. RA,
+ RA - 8, etc. are used for address translation in bndldx. */
+ addr = plus_constant (Pmode, arg_pointer_rtx, -(INTVAL (bnd) + 1) * 8);
+ }
+ else if (MEM_P (slot))
+ {
+ addr = XEXP (slot, 0);
+ addr = force_reg (Pmode, addr);
+ }
+ else
+ gcc_unreachable ();
+
+ ptr = force_reg (Pmode, ptr);
+ /* If ptr was a register originally then it may have
+ mode other than Pmode. We need to extend in such
+ case because bndldx may work only with Pmode regs. */
+ if (GET_MODE (ptr) != Pmode)
+ {
+ rtx ext = gen_rtx_ZERO_EXTEND (Pmode, ptr);
+ ptr = gen_reg_rtx (Pmode);
+ emit_move_insn (ptr, ext);
+ }
+
+ reg = gen_reg_rtx (BNDmode);
+ emit_insn (TARGET_64BIT
+ ? gen_bnd64_ldx (reg, addr, ptr)
+ : gen_bnd32_ldx (reg, addr, ptr));
+
+ return reg;
+}
+
+/* Store bounds BOUNDS for PTR pointer value stored in
+ specified ADDR. If ADDR is a register then TO identifies
+ which special address to use for bounds store. */
+static void
+ix86_store_bounds (rtx ptr, rtx addr, rtx bounds, rtx to)
+{
+ if (!ptr)
+ {
+ gcc_assert (MEM_P (addr));
+ ptr = copy_to_mode_reg (Pmode, addr);
+ }
+
+ if (!addr || REG_P (addr))
+ {
+ gcc_assert (CONST_INT_P (to));
+ addr = plus_constant (Pmode, stack_pointer_rtx, -(INTVAL (to) + 1) * 8);
+ }
+ else if (MEM_P (addr))
+ addr = XEXP (addr, 0);
+ else
+ gcc_unreachable ();
+
+ /* Should we also ignore integer modes of incorrect size?. */
+ ptr = force_reg (Pmode, ptr);
+ addr = force_reg (Pmode, addr);
+
+ /* Avoid registers which connot be used as index. */
+ if (!index_register_operand (ptr, Pmode))
+ {
+ rtx temp = gen_reg_rtx (Pmode);
+ emit_move_insn (temp, ptr);
+ ptr = temp;
+ }
+
+ gcc_assert (POINTER_BOUNDS_MODE_P (GET_MODE (bounds)));
+ bounds = force_reg (GET_MODE (bounds), bounds);
+
+ emit_insn (TARGET_64BIT
+ ? gen_bnd64_stx (addr, ptr, bounds)
+ : gen_bnd32_stx (addr, ptr, bounds));
+}
+
+/* Load and return bounds returned by function in SLOT. */
+static rtx
+ix86_load_returned_bounds (rtx slot)
+{
+ rtx res;
+
+ gcc_assert (REG_P (slot));
+ res = gen_reg_rtx (BNDmode);
+ emit_move_insn (res, slot);
+
+ return res;
+}
+
+/* Store BOUNDS returned by function into SLOT. */
+static void
+ix86_store_returned_bounds (rtx slot, rtx bounds)
+{
+ gcc_assert (REG_P (slot));
+ emit_move_insn (slot, bounds);
+}
+
/* Returns a function decl for a vectorized version of the builtin function
with builtin function code FN and the result vector type TYPE, or NULL_TREE
if it is not available. */
@@ -45796,6 +45997,22 @@ ix86_fn_abi_va_list (tree fndecl)
return sysv_va_list_type_node;
}
+/* This function returns size of bounds for the calling abi
+ specific va_list node. */
+
+static tree
+ix86_fn_abi_va_list_bounds_size (tree fndecl)
+{
+ if (!TARGET_64BIT)
+ return integer_zero_node;
+ gcc_assert (fndecl != NULL_TREE);
+
+ if (ix86_function_abi ((const_tree) fndecl) == MS_ABI)
+ return integer_zero_node;
+ else
+ return TYPE_SIZE (sysv_va_list_type_node);
+}
+
/* Returns the canonical va_list type specified by TYPE. If there
is no valid TYPE provided, it return NULL_TREE. */
@@ -47246,6 +47463,61 @@ ix86_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
atomic_feraiseexcept_call);
}
+static enum machine_mode
+ix86_mpx_bound_mode ()
+{
+ /* Do not support pointer checker if MPX
+ is not enabled. */
+ if (!TARGET_MPX)
+ {
+ if (flag_check_pointer_bounds)
+ warning (0, "Pointer Checker requires MPX support on this target."
+ " Use -mmpx options to enable MPX.");
+ return VOIDmode;
+ }
+
+ return BNDmode;
+}
+
+static tree
+ix86_make_bounds_constant (HOST_WIDE_INT lb, HOST_WIDE_INT ub)
+{
+ tree low = lb ? build_minus_one_cst (pointer_sized_int_node)
+ : build_zero_cst (pointer_sized_int_node);
+ tree high = ub ? build_zero_cst (pointer_sized_int_node)
+ : build_minus_one_cst (pointer_sized_int_node);
+
+ /* This function is supposed to be used to create zero and
+ none bounds only. */
+ gcc_assert (lb == 0 || lb == -1);
+ gcc_assert (ub == 0 || ub == -1);
+
+ return build_complex (NULL, low, high);
+}
+
+static int
+ix86_initialize_bounds (tree var, tree lb, tree ub, tree *stmts)
+{
+ tree size_ptr = build_pointer_type (size_type_node);
+ tree lhs, modify, var_p;
+
+ ub = build1 (BIT_NOT_EXPR, size_type_node, ub);
+ var_p = build1 (CONVERT_EXPR, size_ptr,
+ build_fold_addr_expr (var));
+
+ lhs = build1 (INDIRECT_REF, size_type_node, var_p);
+ modify = build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, lb);
+ append_to_statement_list (modify, stmts);
+
+ lhs = build1 (INDIRECT_REF, size_type_node,
+ build2 (POINTER_PLUS_EXPR, size_ptr, var_p,
+ TYPE_SIZE_UNIT (size_type_node)));
+ modify = build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, ub);
+ append_to_statement_list (modify, stmts);
+
+ return 2;
+}
+
/* Initialize the GCC target structure. */
#undef TARGET_RETURN_IN_MEMORY
#define TARGET_RETURN_IN_MEMORY ix86_return_in_memory
@@ -47642,6 +47914,36 @@ ix86_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
#define TARGET_FLOAT_EXCEPTIONS_ROUNDING_SUPPORTED_P \
ix86_float_exceptions_rounding_supported_p
+#undef TARGET_LOAD_BOUNDS_FOR_ARG
+#define TARGET_LOAD_BOUNDS_FOR_ARG ix86_load_bounds
+
+#undef TARGET_STORE_BOUNDS_FOR_ARG
+#define TARGET_STORE_BOUNDS_FOR_ARG ix86_store_bounds
+
+#undef TARGET_LOAD_RETURNED_BOUNDS
+#define TARGET_LOAD_RETURNED_BOUNDS ix86_load_returned_bounds
+
+#undef TARGET_STORE_RETURNED_BOUNDS
+#define TARGET_STORE_RETURNED_BOUNDS ix86_store_returned_bounds
+
+#undef TARGET_CHKP_BOUND_MODE
+#define TARGET_CHKP_BOUND_MODE ix86_mpx_bound_mode
+
+#undef TARGET_BUILTIN_CHKP_FUNCTION
+#define TARGET_BUILTIN_CHKP_FUNCTION ix86_builtin_mpx_function
+
+#undef TARGET_FN_ABI_VA_LIST_BOUNDS_SIZE
+#define TARGET_FN_ABI_VA_LIST_BOUNDS_SIZE ix86_fn_abi_va_list_bounds_size
+
+#undef TARGET_CHKP_FUNCTION_VALUE_BOUNDS
+#define TARGET_CHKP_FUNCTION_VALUE_BOUNDS ix86_function_value_bounds
+
+#undef TARGET_CHKP_MAKE_BOUNDS_CONSTANT
+#define TARGET_CHKP_MAKE_BOUNDS_CONSTANT ix86_make_bounds_constant
+
+#undef TARGET_CHKP_INITIALIZE_BOUNDS
+#define TARGET_CHKP_INITIALIZE_BOUNDS ix86_initialize_bounds
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-i386.h"